uma
uma

Reputation: 11

Xquery get the children nodes by passing parent value at run time

I need to pass a value at run time get all the childen elements.

For example this is my XML:

<person>
   <details1>
      <name>jack</name>
      <age>26</age>
   </details1>
   <details2>
      <name>john</name>
      <age>48</age>
   </details2>
</person>

And my query:

let $y as xs:string := "details1"
let $x := fn:doc(cts:uri-match('*person.xml'))
return $x/$y

So here I am expecting the result as

<details1>
<name>jack</name>
<age>26</age>
</details1>

but it returns the same name as that of $y i.e. "details1"
or if I query this way

let $y as xs:string := "details1"
let $x := fn:doc(cts:uri-match('*person.xml'))
return $x//$y

the result would be "details1" for 12 times

I am new to XQuery please help me in solving the issue

Upvotes: 1

Views: 2135

Answers (3)

ehennum
ehennum

Reputation: 7335

One alternative is to use xdmp:value() to evaluate the XPath dynamically:

let $y as xs:string := "details1"
let $x := fn:doc(cts:uri-match('*person.xml'))
return xdmp:value("$x/" || $y)

If $x is a large data set, that approach can have performance benefits by removing the need to get the element name for every document in the set.

For more detail, see:

http://docs.marklogic.com/xdmp:value?q=xdmp:value&v=8.0&api=true

Hoping that helps,

Upvotes: 0

Florent Georges
Florent Georges

Reputation: 2327

As drkk said, you have to look at the name of the element. But using name() is dangerous. It returns the lexical name of the element, which might be ns:elem if the element has a prefix. And the prefix can be different in every document, even for the same namespace. So either you match only by local name:

let $y as xs:string := 'details1'
let $x := fn:doc(cts:uri-match('*person.xml'))
return
   $x/*[local-name(.) eq $y]

Or better, match a QName (note the node-name() usage):

let $y as xs:string := xs:QName('details1')
let $x := fn:doc(cts:uri-match('*person.xml'))
return
   $x/*[node-name(.) eq $y]

and if the element name is within a namespace (note the difference between xs:QName() and fn:QName()):

let $y as xs:string := fn:QName('namespace-uri', 'details1')
let $x := fn:doc(cts:uri-match('*person.xml'))
return
   $x/*[node-name(.) eq $y]

Upvotes: 1

dirkk
dirkk

Reputation: 6218

It seems like you attempt to use a string $y as a node step. However, in XPath/XQuery a path step is different from a string, so you can't simple add a string as path step. Instead, you could look for all descendent elements with the requirement that they do have the same name, i.e.:

let $y as xs:string := "details1"
let $x := fn:doc(cts:uri-match('*person.xml'))
return $x/*[name(.) = $y]

Upvotes: 1

Related Questions