2011-06-18 11 views
5

Jestem pewien, że to łatwe, ale po prostu nie widzę drewna dla drzew.Jak liczyć elementy o tej samej wartości atrybutu?

Mam XML, który wygląda tak:

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

teraz chcę wiedzieć, ile/m */@ ia są równe E */@ do za/Profil. Więc wymyśliłem następujący 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> 

Ale wynik jest źle:

<root> 
    <count>1</count> 
    <count>1</count> 
    <count>2</count> 
</root> 

Powinno być

<root> 
    <count>0</count> 
    <count>1</count> 
    <count>1</count> 
</root> 

Czy ktoś ma sugestie co robię źle ?

+0

+1 za dobre pytanie. –

+0

Dobre pytanie, +1. Zobacz moją odpowiedź na kompletne, krótkie i łatwe rozwiązanie, które używa najbardziej odpowiedniej w twoim przypadku standardowej funkcji XPath: 'starts-with()'. :) –

+0

Zmieniłem tytuł, aby lepiej dopasować treść Twojego pytania. bądź wolna, aby powrócić do oryginału, jeśli ci na tym zależy. –

Odpowiedz

6

Wymień XPath z prawidłowym jeden, który jest:

<xsl:value-of select="count(*[substring(name(),1,1)='m' 
     and ./@a = ../*[substring(name(),1,1)='e']/@a])"/> 

Użyłem substring dopasować pierwszy znak atrybutu w miejsce contains która dopasowuje dowolny znak w ciąg.

+0

Dobra odpowiedź - myślę, że 'podciąg 'jest prawdopodobnie bardziej efektywny niż" zawiera ", a ty mnie do niego zbiłeś :) +1 – cordsen

+0

Doskonały i jeszcze lepszy. Dzięki – Sdudda

1

myślę, że to jest to, czego potrzebujesz

count(*[contains(name(), 'm') and (@a = parent::*/*[contains(name(),'e')]/@a)]) 

Stosując ten w 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> 

wywołuje pożądany wynik

<root> 
    <count>0</count> 
    <count>1</count> 
    <count>1</count> 
</root> 
+0

Dzięki tobie również! Działa również perfekt, bo smutno, że tylko długo patrzyłem na ten XSLT. – Sdudda

+0

+1 dla poprawnej odpowiedzi –

0

Zastosowanie (z bieżący węzeł każdy profil element):

count(*[starts-with(name(),'m') 
     and 
     @a = ../*[starts-with(name(),'e')]/@a 
     ] 
    ) 

I kompletny kod XSLT:

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

po naniesieniu na dostarczonym dokumencie XML:

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

produkuje Wanted, poprawny wynik:

<count>0</count> 
<count>1</count> 
<count>1</count> 
Powiązane problemy