<a>
{
for $o in doc("x.xml")/users/org
where fn:count($o/mem)
order by fn:count($o/mem) descending
return <org>
<b> {$o/#name/string()} </b>
<c> {$o/#ab/string()} </c>
<d> {fn:count($o/mem)} </d>
</org>
}
</a>
I have ordered the results in an descending order but I just need top 4 result from this. I tried to use the sub-sequence method on the wiki page and also the [position() 1,4] method to find the top 4 but was not successful.
One possible way using two for loops and limit the inner for to return only the first 4 results :
<a>
{
for $p in
(
for $o in doc("x.xml")/users/org
where fn:count($o/mem)
order by fn:count($o/mem) descending
return <org>
<b> {$o/#name/string()} </b>
<c> {$o/#ab/string()} </c>
<d> {fn:count($o/mem)} </d>
</org>
)[position() <= 4]
return $p
}
</a>
update :
Turns out that we don't actually need the outer for :
<a>
{
(
for $o in doc("x.xml")/users/org
where fn:count($o/mem)
order by fn:count($o/mem) descending
return <org>
<b> {$o/#name/string()} </b>
<c> {$o/#ab/string()} </c>
<d> {fn:count($o/mem)} </d>
</org>
)[position() <= 4]
}
</a>
Related
For example, I want to find all the unique xpath of element in below XML. Can you please help on identifying it using xquery or any other way
<a>
<b>
<identify>Level-1</identify>
</b>
<c>
<identify>Level-2</identify>
<d>
<identify>Level-3</identify>
<e>
<identify>Level-4-1</identify>
<identify>Level-4-2</identify>
</e>
<f>
<identify>Level-4</identify>
<g>
<identify>Level-5</identify>
<identify>Level-5-2</identify>
</g>
</f
</d>
</c>
Your xml is invalid, but assuming you fix it, try this (based on this):
xquery version "3.1";
declare namespace functx = "http://www.functx.com";
declare function functx:path-to-node
( $nodes as node()* ) as xs:string* {
$nodes/string-join(ancestor-or-self::*/name(.), '/')
} ;
let $in-xml :=
<a>
<b>
<identify>Level-1</identify>
</b>
<c>
<identify>Level-2</identify>
<d>
<identify>Level-3</identify>
<e>
<identify>Level-4-1</identify>
<identify>Level-4-2</identify>
</e>
<f>
<identify>Level-4</identify>
<g>
<identify>Level-5</identify>
<identify>Level-5-2</identify>
</g>
</f>
</d>
</c>
</a>
return
functx:path-to-node($in-xml//*[name()="identify"])
Output:
"a/b/identify"
"a/c/identify"
"a/c/d/identify"
"a/c/d/e/identify"
"a/c/d/e/identify"
"a/c/d/f/identify"
"a/c/d/f/g/identify"
"a/c/d/f/g/identify"
There is also the path function: //identify/path() would give
/Q{}a[1]/Q{}b[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}e[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}e[1]/Q{}identify[2]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}f[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}f[1]/Q{}g[1]/Q{}identify[1]
/Q{}a[1]/Q{}c[1]/Q{}d[1]/Q{}f[1]/Q{}g[1]/Q{}identify[2]
for the example in Jack's answer: https://xqueryfiddle.liberty-development.net/nc4P6ya
The format is ugly for XML without namespaces but in other cases has the lengthy but working format to work without setting up any namespace bindings from prefixes to URIs.
I have an xml file in linux that I want to process.
I need to get all ids of a parent nodes based on its children.
Here I want to get all id of 'a' that have 'c' without key "f.g".
<a id="11111">
<b>
<c key="d.e">stuff1</c>
<c key="f.g">stuff2</c>
<c key="j.k">stuff4</c>
</b>
</a>
<a id="22222">
<b>
<c key="d.e">stuff1</c>
<c key="h.i">stuff3</c>
<c key="j.k">stuff4</c>
<c key="l.m">stuff5</c>
</b>
</a>
<a id="33333">
<b>
<c key="c.d">stuff0</c>
<c key="d.e">stuff1</c>
<c key="h.i">stuff3</c>
<c key="j.k">stuff4</c>
<c key="l.m">stuff5</c>
</b>
</a>
In this case I should be getting 22222 and 33333.
I'm not really sure how to write the xpath for this.
I think you are looking for something like:
//a[not(.//c[#key="f.g"])]/#id
which can be translated as: find any node <a> which does NOT have a child node <c> which itself has an attribute called key which itself has an attribute value of "f.g".
You can filter by (not):
//a[[not(#key = 'f.g')]]
It will return you needed 'a' elements, but I don't know how to get their ids.
#Jack Fleeting's answer is probably the best solution. As an alternative (more consuming) :
//c[not(#key="f.g" or preceding-sibling::c[#key="f.g"] or following-sibling::c[#key="f.g"])]/ancestor::a
Look for c elements where itself, and preceding or following siblings contain an attribute different from #key="f.g". Then select their a ancestors.
i want to search for a specific element <B> if <B>'s child <C> equals the string s1 i want to search from that element on to the next element <X> that is NOT a child of <B> and return its value (s2).
The tree would look something like this:
<A>
<B>
<C>s1</C>
</B>
<D>
<X>s2</X>
</D>
</A>
The following works for me in xsh
//X[preceding::B[C='s1']][not(parent::A)]/text()
I have html structure like this:
<a>
<c>
</c>
</a>
<b>
<d>
</d>
</b>
<a>
<c>
</c>
</a>
<b>
<d>
</d>
</b>
How do I group node 'a' and node 'b' together?
The xpath should be able to select the pairs of node 'a' and 'b'.
The nodes have auto generated id's and name's so I can't use them in xpath.
You can use the | operator for two unrelated XPath Expressions:
(//a | //b)
I have a transform that looks like this
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<a>
<b>
<c>
<d>
<e name="UpdateLanguageProfile">
<f xdt:Transform="Replace" xdt:Locator="Condition(/..#name='UpdateLanguageProfile')">
stuff here
</f>
</e>
</d>
</c>
</b>
</a>
So I want the xdt:Locator to select the f node only if the parent node has an attribute with the specified value.
The xdt:Locator gets translated into the following xpath expression:
/a/b/c/d/e/f[/..#name='UpdateLanguageProfile']
Which is invalid.
So the question is, what could I put in the Condition, that is the XPath square brackets, in order to select the f node based on an attribute in the parent node.
The answer is that the xdt:Locator and the xdt:Transform do not need to be on the same node. They just happen to be on the same node in every example I've ever seen.
You can do this:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<a>
<b>
<c>
<d>
<e name="UpdateLanguageProfile" xdt:Locator="Match(name)">
<f xdt:Transform="Replace">
stuff here
</f>
</e>
</d>
</c>
</b>
</a>