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,
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
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
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> )
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.
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
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.
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.
On Fri, Jul 11, 2014 at 12:48 PM, Paul Swennenhuis paul@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' } )
basex-talk@mailman.uni-konstanz.de