开发者

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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜