Reputation: 397
Sample XML document:
<?xml version="1.0"?>
<names>
<name>abc</name>
<name>abc</name>
<name>xyz</name>
<name>def</name>
<name>ghi</name>
</names>
Output needed as:
abc: 2
xyz: 1
def: 1
ghi: 1
Tried the below XPath expression :-
for $n in //names/name return concat($n, ': ', count(//$n))
But output comes like this:
abc: 1
abc: 1
xyz: 1
def: 1
ghi: 1
Upvotes: 3
Views: 962
Reputation: 243529
A shorter and simpler XPath 2.0 solution (no distinct-values()
, no concat()
):
for $v in /*/*[index-of(/*/*, .)[1]]/node()
return ($v, ':', count(index-of(/*/*, $v)), '
')
XSLT - based verification:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select=
"for $v in /*/*[index-of(/*/*, .)[1]]/node()
return ($v, ':', count(index-of(/*/*, $v)), '
')"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<names>
<name>abc</name>
<name>abc</name>
<name>xyz</name>
<name>def</name>
<name>ghi</name>
</names>
The XPath expression is evaluated and the result of this evaluation is copied to the output:
abc: 2
xyz: 1
def: 1
ghi: 1
Upvotes: 0
Reputation: 167706
XPath 3.1 would be
map:merge(
/names/name!map{ string() : .},
map { 'duplicates': 'combine'})
=>
map:for-each(function($k, $v) {
$k || ': ' || count($v)
})
In XPath 2:
for $distinct-name in distinct-values(/names/name)
return concat($distinct-name, ': ', count(/names/name[. = $distinct-name]))
Upvotes: 3