How to count elements with same attribute value
I'm sure this is an easy one but i'm just not to see the wood for the trees.
I'm having an XML that look like this:
<root>
<profil>
<e1 a="2">1</e1>
<m1 a="3">1</m1>
<e2 a="4">1</e2>
<m2 a="5">1</m2>
</profil>
<profil>
<e1 a="5">1</e1>
<m1 a="3">1</m1>
<e2 a="4">1</e2>
<m2 a="4">1</m2>
</profil>
<profil>
<e1 a="7">1</e1>
<m1 a="7">1</m1>
<e2 a="4">1</e2>
<m2 a="2">1</m2>
</profil>
</root>
Now I want to know how many /m*/@a are equal to e*/@a per /profil. So I came up with the following XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<xsl:element name="root">
<xsl:for-each select="/root/profil">
<xsl:element name="count">
<xsl:value-of select="count(*[contains(name(), 'm') and ./@a = //*[contains(name(),'e')]/@a])"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
But the result is wrong:
<root>
<count>1</count>
<count>1</count>
<count>2</count>
</root>
It should be
<root>
<count>0</count>
<count>1</count>
<count>1</co开发者_运维百科unt>
</root>
Does anyone has a suggestion what I'm doing wrong?
Replace the XPath with the correct one, which is:
<xsl:value-of select="count(*[substring(name(),1,1)='m'
and ./@a = ../*[substring(name(),1,1)='e']/@a])"/>
I've used substring
to match the first attribute character in place of contains
which matches any character in a string.
I think this is what you need
count(*[contains(name(), 'm') and (@a = parent::*/*[contains(name(),'e')]/@a)])
Using this in your XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="*">
<xsl:element name="root">
<xsl:for-each select="/root/profil">
<xsl:element name="count">
<xsl:value-of select="count(*[contains(name(), 'm') and (@a = parent::*/*[contains(name(),'e')]/@a)])"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
produces the desired output
<root>
<count>0</count>
<count>1</count>
<count>1</count>
</root>
Use (with current node any profil
element):
count(*[starts-with(name(),'m')
and
@a = ../*[starts-with(name(),'e')]/@a
]
)
And the complete XSLT code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="profil">
<count>
<xsl:value-of select=
"count(*[starts-with(name(),'m')
and
@a = ../*[starts-with(name(),'e')]/@a
]
)
"/>
</count>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<profil>
<e1 a="2">1</e1>
<m1 a="3">1</m1>
<e2 a="4">1</e2>
<m2 a="5">1</m2>
</profil>
<profil>
<e1 a="5">1</e1>
<m1 a="3">1</m1>
<e2 a="4">1</e2>
<m2 a="4">1</m2>
</profil>
<profil>
<e1 a="7">1</e1>
<m1 a="7">1</m1>
<e2 a="4">1</e2>
<m2 a="2">1</m2>
</profil>
</root>
produces the wanted, correct result:
<count>0</count>
<count>1</count>
<count>1</count>
精彩评论