How to count elements with same name? XML -> Xquery
i have a xml doc like:
<root>
<test>
<humans>
<names>Tim</names>
</humans>
</test>
<test>
<humans>
<names>Jack</names>
<names>Jones</names>
</humans>
</test>
<test>
<humans>
<names>Tim</names>
</humans>
</test>
</root>
and I want to count all names which are the same: Tim 2, Jack 1, Jones 1 and it should give an output like:
<x> Tim </x>
because TIM is the highest name
I hope you can hel开发者_Go百科p me... (sorry for my bad english)
In XPath 2.0, XSLT 2.0 and XQuery use (exactly the same solution):
(/*/*/*/names[for $v in .,
$cnt in count(/*/*/*/names[. eq $v])
return
$cnt
eq
max(for $n in distinct-values(/*/*/*/names)
return
count(/*/*/*/names[. eq $n])
)
]
)[1]
You can also get this element easily with the following XSLT 1.0 transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kNamesByVal" match="names" use="."/>
<xsl:template match="/">
<xsl:for-each select=
"*/*/*/names[generate-id()
=
generate-id(key('kNamesByVal',.)[1])
]">
<xsl:sort select="count(key('kNamesByVal',.))"
data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When the above XPath 2.0/XQuery expression or XSLT transformation are evaluated (applied) on the provided XML document:
<root>
<test>
<humans>
<names>Tim</names>
</humans>
</test>
<test>
<humans>
<names>Jack</names>
<names>Jones</names>
</humans>
</test>
<test>
<humans>
<names>Tim</names>
</humans>
</test>
</root>
the correct element is selected (produced):
<names>Tim</names>
let $xml := <!-- your xml document -->
return
(
for $name in distinct-values($xml//names)
order by count($xml//names[. = $name]) descending
return <x>{$name}</x>
)[1]
The solution of Gunther is the best, and if you wanted to count every elements you could do:
xquery version "1.0";
for $x in
(
for $name in distinct-values(//names)
order by count(//names[. = $name]) descending
return <x>{$name}</x>
) return fn:concat($x, ' - ',xs:string(count(//names[. = $x])))
With result Tim - 2 Jack - 1 Johons - 1
精彩评论