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
How to Get the Day of Week and the Month of the Year
How to Break a String Across More Than One Line of Code in JavaScript
How to Toggle an Element's Class in Pure JavaScript
JavaScript - How to Extract Filename from a File Input Control
Set Additional Data to Highcharts Series
Jquery (Or Pure Js) Simulate Enter Key Pressed for Testing
Jquery Selector for Id Starts with Specific Text
Invalid Hook Call. Hooks Can Only Be Called Inside of the Body of a Function Component
What's the Cause of the Error 'Getaddrinfo Eai_Again'
How to Change the Content of a <Textarea> with JavaScript
Chrome, JavaScript, Window.Open in New Tab
Failed to Execute 'Postmessage' on 'Domwindow': Https://Www.Youtube.Com !== Http://Localhost:9000
How to Parse JSON to Receive a Date Object in JavaScript