chriskelly
chriskelly

Reputation: 7736

xpath for JSON not the same as XML

I'm trying to XPath into some JSON using the same technique I would use to access XML. Below are 2 equivalent structures with the same XPath applied.

let $json := xdmp:unquote('{
  "foo": {
    "bar": {
      "bas": "findme",
      "boo": "324"
    }
  }
}')

let $xml := <xml>
  <foo>
    <bar>
      <bas>findme</bas>
      <boo>324</boo>
    </bar>
  </foo>
</xml>

return (
    $xml//node()[./text() = "findme"], 
    $json//node()[./text() = "findme"]
)

I would expect the same result for both but I get the following:

XML Result

<bas>findme</bas>

JSON result

{ "bas": "findme", "boo": "324" }

Why does this not produce the same result?

Upvotes: 2

Views: 501

Answers (1)

grtjn
grtjn

Reputation: 20414

In MarkLogic the text property bas is a named text node, something that doesn't exist in XML space. It is designed such that something like //bas would work for both. Because of the named text node, the tree structure is different at deepest level:

element bas {
  text { "findme" }
},
element boo {
  text { "324" }
}

Versus:

object-node {
  text bas { "findme" },
  text boo { "324" }
}

Note: the latter is pseudo-code. Correct use of JSON constructors would be: object-node { "bas": "findme", "boo": "324" }.

There might be a way to get closer to what you are after by making use of fn:name() (fn:local-name() doesn't work here, by the way). Try something like:

let $json := xdmp:unquote('{
  "foo": {
    "bar": {
      "bas": "findme",
      "boo": "324"
    }
  }
}')

let $xml := <xml>
  <foo>
    <bar>
      <bas>findme</bas>
      <boo>324</boo>
    </bar>
  </foo>
</xml>

let $xml-text := $xml//text()[. = "findme"]
let $json-text := $json//text()[. = "findme"]
for $t in ($xml-text, $json-text)
return
  if (name($t) eq "") then
    $t/..
  else
    object-node { name($t): $t }

HTH!

Upvotes: 3

Related Questions