We're adding JSON output to an existing API that outputs XML, to make MobileHTML integration much easier. However, our developer has queried the use of #attributes appearing in the JSON output.
Our original XML looks like:
<markers>
<marker id="11906" latitude="52.226578"
...
and so the JSON comes out as:
callbackname({"marker":[{"#attributes":{"id":"11906","latitude":"52.226578"
....
Our developer has stated:
"Although '#attributes' is legal JSON, it seems to break dot notation, so I can't call data.#attributes. I can call data['#attributes'], so there's a workaround, but it seems safer just to avoid the #-symbol, unless there's a good reason for it."
The XML->JSON(P) conversion is done using:
$xmlObject = simplexml_load_string ($data);
$data = json_encode ($xmlObject);
I want to make our API as easy-to-integrate as possible, and therefore to use standard stuff where possible. But we're using the native PHP json_encode function, so I'd be surprised if it's doing something non-standard.
Is use of #attributes non-standard? Is this basically just the problem that our API is a bit broken in terms of using <marker id..> rather than <marker><id> ?
The JSON standard only specifies what is and isn't valid; it doesn't set convention. There's nothing inherently wrong with using property names which aren't valid Javascript identifiers.
However, as your developer points out, this does make it slightly more awkward to use the result in JS, as it makes it impossible to use dot notation. On the gripping hand, using attributes for simple content is usually seen as "good XML" and you're using using default, built-in tools to convert from XML to JSON. I'd tend to consider that a good enough reason to leave it as it is.
If it were me, I'd look at how difficult it would be to implement a custom XML -> JSON converter. If it's simple and straightforward, go that route and avoid #attribute (it will also likely make your JSON smaller and simpler). If it's too much hassle, however, missing out on dot notation isn't the end of the world. At worst, var attr = data.marker["#attributes"]; will get around the issue.
Related
I am working on a demo using MarkLogic to store emails exported from Outlook as XML, so that they stay searchable and accessible when I move away from Outlook.
I am using an AngularJS front-end calling either the native MarkLogic REST services of own REST services written in JAVA using Jersey.
MarkLogic SEARCH REST service works very well to get back a list of references to documents based on various search criteria, but I also want to display information stored inside the found documents.
I would like to avoid multiple REST calls and to get back only the needed information, so I am trying to use the EVAL REST service to run an xQuery.
It works well to get XML back (inside a multipart/mixed message) but I don't seem to be able to get JSON instead which would be much more convenient and is very easy with most other MarkLogic REST services.
I could use "json:transform-to-json()" in my xQuery or transform the XML to JSON in my JAVA code, but that does not look very elegant to me.
Is there a more efficient method to get where I am trying to go ?
First, json:transform-to-json seems plenty elegant to me. But of course it's not always the right answer.
I see three options you haven't mentioned.
server-side transforms - REST search supports server-side transforms which transform each document when you perform a bulk read by query. Those server-side transforms could generate any json you need.
search extract-document-data - this the simplest way to extract portions of documents. But it seems best if your documents are json to match your json response. Otherwise you get xml in your json response . . . unless you're ok with that.
custom search snippets - another very powerful way to customize what search returns
All of these options don't require the privileges that eval requires, which is a very good thing. Since eval allows execution of arbitrary code on your server, it requires special privileges and should be used with great care. Two other options before you use eval are (1) custom xquery installed in an http server, and (2) REST extensions.
The answers from Sam are what I would suggest. Specifically I would set a search option for search-extract-document-data (This is a search API option. If you are posting the request, then you can add the option in the XML you post back. If you are using GET, then you need to register the option ahead of time and call it. Relevant URLs to assist:
https://docs.marklogic.com/guide/rest-dev/search#id_48838
https://docs.marklogic.com/guide/search-dev/appendixa#id_44222
As for json.. ML8 will transform content. Use the accept-header or just add format=json to your results...
Example - xml which is what my content is stored as:
http://localhost:8000/v1/search?q=watermellon
...
<search:result index="1" uri="/sample/collections/1.xml" path="fn:doc("/sample/collections/1.xml")" score="34816" confidence="0.5982239" fitness="0.6966695" href="/v1/documents?uri=%2Fsample%2Fcollections%2F1.xml" mimetype="application/xml" format="xml">
<search:snippet>
<search:match path="fn:doc("/sample/collections/1.xml")/x">
<search:highlight>watermellon</search:highlight>
</search:match>
</search:snippet>
</search:result>
...
Example - json which is what my content is stored as:
http://localhost:8000/v1/search?q=watermellon&format=json
...
"index":1,
"uri":"/sample/collections/1.xml",
"path":"fn:doc(\"/sample/collections/1.xml\")",
"score":34816,
"confidence":0.5982239,
"fitness":0.6966695,
"href":"/v1/documents?uri=%2Fsample%2Fcollections%2F1.xml",
"mimetype":"application/xml",
"format":"xml",
"matches":[
{
"path":"fn:doc(\"/sample/collections/1.xml\")/x",
"match-text":[
{
"highlight":"watermellon"
}
]
}
]
}
...
For real heavy-lifting, you can use server-side transforms as in Sam's description. One note about this. Server-side transformations are not part of the search API, but part of the REST API. Just mentioning it so you have some idea of which tool you are using in each case..
Is it advisable or not in a RESTful web service to use JSON literal values (string / number) as input parameter in the payload or in the response body?
If I have an endpoint PUT /mytodolist is it OK for it to accept a JSON string literal value "Take out the rubbish" in the request payload (with Content-Type=application/json) or should it accept a JSON object instead ({"value":"Take out the rubbish"})?
Similarly, is it fine for GET /mytodolist/1 to return "Take out the rubbish" in the response body or should it return a proper JSON object {"value":"Take out the rubbish"}
Spring MVC to makes implementing and testing such endpoints easy, however clients have flagged this as non standard or hard to implement. In my point of view JSON literals are JSON, but not JSON objects, so I'd say it is fine. I have found no recommendations using Google.
EDIT 1: Clafirication
The question is entirely about the 'standard', if it allows this or not.
I understand the problem with the extensibility, but one can never design a fully extensible interface IMHO. If changes need to be done, we can try extending what we have in a backwards compatible way, but there will come a time when it becomes messy and an other approach is required - which is commonly handled by versioning the API in one way or another. I find it a fair point even though, because using literals as request/response body immediately becomes inextensible, while coming up with a reasonable one-attribute JSON object does not.
It is also understood that some frameworks have problems with handling JSON literals, this is the origin of this question. The tool I used happened to support this, so I thought this was all right, but the front-end library did not.
Still, what I am intending to find out right now, is if using JSON literals is according to the de-facto standard (even if it is a cornercase) or not.
I would recommend to use JSON object always. One reason is that for Content-Type application/json people expect something staring with "{" and not all frameworks will handle json literals properly. Second reason is that probably you will add some additional attributes to you list item (due date, category, priority, etc). And then you'll break backward compatibility, by adding new field.
It may be acceptable in the context of your example, but keep in mind that unambiguous interfaces are easier to use and that will encourage adoption.
For example, your interface could interpret "Take out he rubbish" as the same as {task:"take out the rubbish"}, but once you add additional properties (eg "when" or "who") the meaning of a solitary string in the request becomes ambiguous. It's inevitable that you'll add support for new properties as your interface matures.
I'm trying to return an html snippet from a service that can only return valid JSON.
I've tried some things like:
This gets me a bunch of character like \n\n\n\n\t\t\t\t
return JSON.stringify({html: $('body').html()});
or
return JSON.stringify($('body').html());
On the receiving end, I'd like to be able to parse that HTML via Cheerio, or jQuery or JSDom so I can then run queries like $(".some_selector") on that data.
What is the proper way of doing this? Any special libraries / methods that can handle the escaping for me? I've googled it, but haven't had any clear results...
Thanks.
On the receiving end, you need to simply undo the JSON serialization. That's it!
Your HTML will be in its regular format at obj.html, which you can then parse with whatever DOM parser you want.
Well, you are probably going to need to worry about quotes in the HTML (like with attributes) because the could interfere with the quotes that delimit your JSON values.
Here is similar question as well as this web page that explains some of what you need to consider.
Briefly looking at npmsj.org, I didn't see any reputable modules that might help you make HTML JSON compatible, but I think you can probably figure it out fairly easily on your own, given a large enough sample set of HTML. You can always run your JSON through this validator to check it. I suppose you could also simply do a JSON.parse(jsonContainingHtml) on it as well. You'll get an exception if the string is not valid JSON.
I would like to send erlang terms (erlang-based back end) to the web browser. It is easy enough to encode a term on the erlang side using something like:
term_to_binary(Term)
or:
binary_to_list(term_to_binary(Term))
The problem of course is that scrambled garbage shows up on the browser end.
Question: Is there either some encoding I can use on the browser end, or more likely, some Content-Type I can accept on the browser end to unscramble this?
Thanks.
Use io_lib:format("~p",[Term]). It will produce a string representation of the erlang term which can be showed on a web page. Consider also checking out this question and its answer.
There is piqi that provides extensive mapping mechanisms between .piqi (its record definition language), json, xml and protobuf. It's a really cool tool, that we use all the time to map between all of these formats.
Typically when I build something (in Erlang) that needs to provide some sort of data to something else, I start with a piqi definition file that defines the structure. The piqic compiler generates Erlang record definitions and conversion code to do conversions easily.
Highly recommended, but it might be overkill for what you're doing.
Encode it with base64. Get it via ajax, then decode either with native window.atob or any of numerous available libs.
If it is for a web browser, I would go for a Json string, it's unicode and browsers support it nativaly.
Maybe consider Json and do something like this for strings:
1> HelloJerome = "Hello Jérôme".
"Hello Jérôme"
2> HelloJeromeBin = list_to_binary(HelloJerome).
<<"Hello Jérôme">>
3> HelloJeromeJson = << <<"{\"helloJerome\":\"">>/bits, HelloJeromeBin/bits, $\", $} >>.
<<"{\"helloJerome\":\"Hello Jérôme\"}">>
In the browser console:
jerome = JSON.parse('{\"hello\":\"Hello Jérôme\"}')
Now
jerome.hello == "Hello Jérôme"
There are some good lib out there ejson or mochijson2 are the classic ones but ktuo or ...
{ members: [
[
{
c1: [{fft: 5,v: 'asdead#asdas.com'}],
c2: [{fft: 9,v: 'tst'}],
c3: [{sft: 1,v: 'Corporate Member'}]},
{
c1: [{fft: 5,v: 'asdk#asda.com'}],
c2: [{fft: 9,v: 'asd'}],
c3: [{sft: 1,v: 'Company'}]}
...etc
What is this JSON format? The full version is here.
It just doesn't look like any other JSON I've seen. I would be very thankful for a pointer in the right direction to parse this. So long as it's not just regex it, which I'm sure is possible but not something I can accomplish.
This appears to be the result of an ASP .NET web service based on the .asmx in the URL. What looks non-standard to me (based on the http://www.json.org/ definition) is the lack of double-quotes around the keys, and single-quotes instead of double-quotes wrapping the string values. E.g. v: 'asdk#asda.com' should be "v": "asdk#asda.com". I believe this is object literal notation of JavaScript (http://www.dyn-web.com/tutorials/obj_lit.php) rather than strict JSON, which is itself a subset of object literal notation.
How you choose to parse it could depend on what language/platform constraints you have, but I believe JavaScript will handle it. For an example, see this JSON/JavaScript code on Google Code Playground: http://code.google.com/apis/ajax/playground/#json_data_table. It constructs a JSON object using object literal notation for its visualization service.
Judging by this question and its followup on the Wild Apricot forums, you're poking at an undocumented tool primarily intended for internal use. Your best bet is to leave it alone. Your second-best bet is to hack at an existing parser in whatever language you are handling this with so that the parser tolerates unquoted keys.
You would probably be best off using a standard JSON library to parse it. A full list, organized by platform, is available at the json.org site.
That's not JSON. It actually looks like a lua source code encoding of the data. But if it is undocumented, it could be anything, so you're probably not going to be able to handle it reliably.