Is There a JSON Equivalent of Xquery/Xpath

Is there a JSON equivalent of XQuery/XPath?

Yup, it's called JSONPath:

It's also integrated into DOJO.

Using saxon & XPath 3.1 to parse JSON files

Technically, you don't run queries against JSON files; you run them against the data structure that results from parsing a JSON file, which is a structure of maps and arrays. You can parse the JSON file using the parse-json() or json-doc() functions, and then query the result using operators that work on maps and arrays. Some of these (and examples of their use) are shown in the spec at

https://www.w3.org/TR/xpath-31/#id-maps-and-arrays

Googling for "query maps arrays JSON XPath 3.1" finds quite a lot of useful material. Or get Priscilla Walmsley's book: http://www.datypic.com/books/xquery/chapter24.html

Data types: the data types of string, number, and boolean that are intrinsic to JSON are automatically recognized by their form. There's no capability to do further typing using a schema.

XQuery is a superset of XPath, but as far as JSON/Maps/Arrays are concerned, I think the facilities in XPath and those in XQuery are exactly the same.

Saxon has added a bit of extra conformance and performance in each successive release. 9.9 is pretty complete in its coverage; 10.0 adds some optimizations (like a new internal data structure for maps whose keys are all strings, such as you get when you parse JSON). Details of changes in successive Saxon releases are described in copious detail at http://www.saxonica.com/documentation/index.html#!changes

I want to write the XQuery to print the specific keys in JSON

Not knowing how you are reading the JSON document, whether as a doc in the database or parsing a JSON string, below uses xdmp:unquote() to parse a string, but you could instead just read the document from the database with fn:doc() or through cts:search().

Then, you could just XPath to the transation fields and return those node names with the name() function:

let $jsonData := xdmp:unquote('
{
"id":"743",
"groupName":"group1",
"transation":{
"101":"success",
"102":"rejected",
"301":"processing"
}
}')
return
$jsonData/transation/*/name()

XSLT equivalent for JSON

Interesting idea. Some searching on Google produced a few pages of interest, including:

  • an outline of how such a "jsonT" tool might be implemented, and some downloads
  • some discussion of that implementation
  • a company which may have implemented something suitable

Hope this helps.

How to get data with nested JSON without create a lots of map method

Sounds like you want to use JSONPath, see the accepted answer here:
Is there a JSON equivalent of XQuery/XPath?

and go over https://code.google.com/archive/p/jsonpath/ for some syntax examples.

JSONPath is to JSON what X-Path is to XML.

For your case something like:

jsonPath(yourJsonObj, $.activities.trackingProgress.items._id)

If you are using ES6,
then install it from NPM and import it

https://www.npmjs.com/package/jsonpath

xquery/xpath comparing all but a specific node

I would normalize the content, removing the elements that you don't want to compare, and then use fn:deep-equal() to compare the normalized documents.

Below is an example of how you can use XSLT to remove the elements with xdmp:xslt-eval() (you could also xdmp:xslt-invoke an installed stylesheet instead of eval):

xquery version "1.0-ml";

declare function local:compare($a, $b) {
let $xslt :=
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--Remove the elements that we don't want to compare -->
<xsl:template match="ingestDate | itemRecordingTime"/>
</xsl:stylesheet>
let $normalized-a := xdmp:xslt-eval($xslt, $a)
let $normalized-b := xdmp:xslt-eval($xslt, $b)
return fn:deep-equal($normalized-a, $normalized-b)
};

let $doc-a :=
<record>
<core>
<title>test1</title>
<description>testDesc1</description>
<ingestDate>2019-03-01</ingestDate>
</core>
<specialized>
<item>testItem1</item>
<itemRecordingTime>2019-12-05T08:15:00</itemRecordingTime>
</specialized>
</record>
let $doc-b :=
<record>
<core>
<title>test1</title>
<description>testDesc1</description>
<ingestDate>2020-03-01</ingestDate>
</core>
<specialized>
<item>testItem1</item>
<itemRecordingTime>2020-12-05T08:15:00</itemRecordingTime>
</specialized>
</record>

return
local:compare($doc-a, $doc-b)


Related Topics



Leave a reply



Submit