JSON output in PHP client
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
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
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 >
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 > >
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> > )
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> >> ) >
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' } > )
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.