JSON output in PHP client
Friday, 11 July 2014 · 8 messages
PS
Paul Swennenhuis11 Jul 2014 10:21 #
I've been playing a bit with BaseX the last couple of days - and very excited about the product while doing so - but now I am having problems outputting JSON from a PHP script.
I have this XQuery:
declare option output:method "json";
declare option output:json "format=jsonml";
<json type="object">
{
for $user in collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<testResults>
<testId>{$user/test/_id}</testId>
<grade>{$user/user_info/user_grade}</grade>
</testResults>
}
</json>In the BaseX GUI this yields:
["json", {"type":"object"},
["testResults",
["testId",
["_id",
"Bio-1"]],
["grade",
["user_grade",
"7"]]],
["testResults",
["testId",
["_id",
"Bio-2"]],
["grade",
["user_grade",
"1"]]]]Which is what I expected after reading about the JSONML format. (Not too happy with that format, but that's another story).
Running exactly the same XQuery form within a PHP script however yields this:
<json type="object">
<testResults>
<testId>
<_id>Bio-1</_id>
</testId>
<grade>
<user_grade>7</user_grade>
</grade>
</testResults>
<testResults>
<testId>
<_id>Bio-2</_id>
</testId>
<grade>
<user_grade>1</user_grade>
</grade>
</testResults>
</json>(script is attached; note that the $ signs have been escaped there so that PHP will not try to evaluate them)
In other words, the result is being output as XML with an enclosing <json> root tag, not as JSON.
What is happening here? And how can I have BaseX return JSON from PHP?
Paul Swennenhuis
CG
Christian Grün11 Jul 2014 10:35 #
Hi Paul,
Quoted text · Paul Swennenhuis · 2 lines
> Which is what I expected after reading about the JSONML format. (Not too > happy with that format, but that's another story).
I agree; JSONML is a quasi-standard we have adopted, which is mainly useful for converting arbitrary XML to JSON. If you can decide how your XML format looks like, I would recommend the standard conversion format:
declare option output:method "json";
<json type="array" objects='_'>{
for $user in
collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<testResults>
<testId>{$user/test/_id}</testId>
<grade>{$user/user_info/user_grade}</grade>
</testResults>
}</json>Quoted text · Paul Swennenhuis · 3 lines
> Running exactly the same XQuery form within a PHP script however yields > this:
The query results are currently sent to all clients in their standard format (i.e., ignoring all serialization parameters). That's why you'll need to convert your JSON within XQuery:
json:serialize(
<json type="array" objects='_'>{
...
}</json>
)If I remember what was the reason for that design decision, I'll give you an update soon..
Hope this helps,
Christian
PS
Paul Swennenhuis11 Jul 2014 11:17 #
Hi Christian,
Thanks for the quick answer.
Unfortunately your proposed solution (
json:serialize) does not work in this case; BaseX returns a BXJS0002 error:
JSON serializer: found, <_> expected.
The modified query reads:json:serialize(
<json type="array" objects='_'>{
for \$user in collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<testResult>
<testId>{\$user/test/_id}</testId>
<grade>{\$user/user_info/user_grade}</grade>
</testResult>
}
</json>
)Paul
Quoted text · Christian Grün · 42 lines
> Hi Paul, > > > Which is what I expected after reading about the JSONML format. (Not too > > happy with that format, but that's another story). > > I agree; JSONML is a quasi-standard we have adopted, which is mainly > useful for converting arbitrary XML to JSON. If you can decide how > your XML format looks like, I would recommend the standard conversion > format: > > declare option output:method "json"; > > <json type="array" objects='_'>{ > for $user in > collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] > return > <testResults> > <testId>{$user/test/_id}</testId> > <grade>{$user/user_info/user_grade}</grade> > </testResults> > }</json> > > > > Running exactly the same XQuery form within a PHP script however yields > > this: > > The query results are currently sent to all clients in their standard > format (i.e., ignoring all serialization parameters). That's why > you'll need to convert your JSON within XQuery: > > json:serialize( > <json type="array" objects='_'>{ > ... > }</json> > ) > > If I remember what was the reason for that design decision, I'll give > you an update soon.. > > Hope this helps, > Christian >
CG
Christian Grün11 Jul 2014 11:49 #
I should have run your query before sending you an answer. The following query should work:
json:serialize(
<json type="array" objects='_'>{
for $user in
collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<_>
<testId>{$user/test/_id}</testId>
<grade>{$user/user_info/user_grade}</grade>
</_>
}</json>
)Quoted text · Paul Swennenhuis · 41 lines
> >> Which is what I expected after reading about the JSONML format. (Not too >> happy with that format, but that's another story). > > I agree; JSONML is a quasi-standard we have adopted, which is mainly useful > for converting arbitrary XML to JSON. If you can decide how your XML format > looks like, I would recommend the standard conversion format: > > declare option output:method "json"; > > <json type="array" objects='_'>{ > for $user in > collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] > return > <testResults> > <testId>{$user/test/_id}</testId> > <grade>{$user/user_info/user_grade}</grade> > </testResults> > }</json> > >> > Running exactly the same XQuery form within a PHP script however yields >> this: > > The query results are currently sent to all clients in their standard format > (i.e., ignoring all serialization parameters). That's why you'll need to > convert your JSON within XQuery: > > json:serialize( > <json type="array" objects='_'>{ > ... > }</json> > ) > > If I remember what was the reason for that design decision, I'll give you an > update soon.. > > Hope this helps, > Christian > >
PS
Paul Swennenhuis11 Jul 2014 12:13 #
Still no luck:
JSON serializer: <testId> is typed as "string" and cannot be nested
I think I am going to move the JSON conversion to within PHP or Javascript, and keep the XQueries clean and readable.
Quoted text · Christian Grün · 12 lines
Paul > json:serialize( > <json type="array" objects='_'>{ > for $user in > collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] > return > <_> > <testId>{$user/test/_id}</testId> > <grade>{$user/user_info/user_grade}</grade> > </_> > }</json> > )
DK
Dirk Kirsten11 Jul 2014 12:41 #
Hi Paul,
no need to despair ;)
The default JSON converter is the direct one (which would require <testId/> to be declared an object), not JsonML. If you you want to use JsonML you can do so by using
json:serialize(
<json type="array" objects='_'>{
for $user in
collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<_>
<testId>{$user/test/_id}</testId>
<grade>{$user/user_info/user_grade}</grade>
</_>
}</json>,
map { 'format': 'jsonml' }
)For some more information you can take a look at
https://docs.basex.org/wiki/JSON_Module
Cheers,
Dirk
Quoted text · Paul Swennenhuis · 21 lines
On 11/07/14 12:13, Paul Swennenhuis wrote: > Still no luck: > JSON serializer: <testId> is typed as "string" and cannot be nested > > I think I am going to move the JSON conversion to within PHP or > Javascript, and keep the XQueries clean and readable. > > Paul >> json:serialize( >> <json type="array" objects='_'>{ >> for $user in >> collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] >> >> return >> <_> >> <testId>{$user/test/_id}</testId> >> <grade>{$user/user_info/user_grade}</grade> >> </_> >> }</json> >> ) >
--
Dirk Kirsten, BaseX GmbH, http://basex.org
|-- Firmensitz: Blarerstrasse 56, 78462 Konstanz
|-- Registergericht Freiburg, HRB: 708285, Geschäftsführer:
| Dr. Christian Grün, Dr. Alexander Holupirek, Michael Seiferle `-- Phone: 0049 7531 28 28 676, Fax: 0049 7531 20 05 22
PS
Paul Swennenhuis11 Jul 2014 12:48 #
Ah, yes, that did the trick. I read about the options but had forgotten about it.
Thanks.
I will run some performance tests to decide for
json:serialize or PHP internal conversion which might be considerably slower.Quoted text · Dirk Kirsten · 13 lines
Paul > json:serialize( > <json type="array" objects='_'>{ > for $user in > collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] > return > <_> > <testId>{$user/test/_id}</testId> > <grade>{$user/user_info/user_grade}</grade> > </_> > }</json>, > map { 'format': 'jsonml' } > )
CG
Christian Grün11 Jul 2014 14:54 #
Hi Paul, and thanks Dirk.
One last note: If you plan to stick with JsonML, you can serialize arbitrary XML data, such as..
json:serialize(
<xml>{
for $user in
collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"]
return
<result>
<testId>{$user/test/_id}</testId>
<grade>{$user/user_info/user_grade}</grade>
</result>
}</xml>,
map { 'format': 'jsonml' }
)C.
Quoted text · Paul Swennenhuis · 23 lines
On Fri, Jul 11, 2014 at 12:48 PM, Paul Swennenhuis <paul at swennenhuis.nl> wrote: > Ah, yes, that did the trick. I read about the options but had forgotten > about it. > Thanks. > I will run some performance tests to decide for json:serialize or PHP > internal conversion which might be considerably slower. > > Paul >> >> json:serialize( >> <json type="array" objects='_'>{ >> for $user in >> collection("saveresult")//user[_id="1f2cda8f-a18a-44ba-8d17-73626d472306"] >> return >> <_> >> <testId>{$user/test/_id}</testId> >> <grade>{$user/user_info/user_grade}</grade> >> </_> >> }</json>, >> map { 'format': 'jsonml' } >> ) > >
Written for BaseX 7.9. BaseX may have changed since: please check the current documentation.
⚡Generated with XQuery