2011-06-18 33 views
5

Estoy seguro de que este es fácil, pero simplemente no veo la madera para los árboles.Cómo contar elementos con el mismo valor de atributo

estoy teniendo un XML que se parecen a esto:

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

Ahora quiero saber cuántos/m */@ a es igual a E */@ A por/profil. Así me ocurrió con la siguiente 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> 

Pero el resultado es falso:

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

Cabe

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

¿Alguien tiene una sugerencia de lo que estoy haciendo mal ?

+0

+1 para la buena pregunta. –

+0

Buena pregunta, +1. Vea mi respuesta para una solución completa, corta y fácil que utiliza la función XPath estándar más adecuada en su caso: 'starts-with()'. :) –

+0

He cambiado el título para que coincida mejor con el contenido de su pregunta. puede volver al original si le interesa. –

Respuesta

6

Reemplazar el XPath con la correcta, que es:

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

He usado substring para que coincida con el primer carácter de atributo en lugar de contains que coincide con cualquier carácter en una cadena.

+0

Buena respuesta - Creo que 'substring' es probablemente más eficiente que' contains' y me ganas :) +1 – cordsen

+0

Perfecto y aún mejor. Gracias – Sdudda

1

creo que esto es lo que necesita

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

El uso de este en su 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> 

produce la salida deseada

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

Gracias a ti también! Funciona también perfectamente ya que me entristece solo mirar durante mucho tiempo ese XSLT. – Sdudda

+0

+1 para la respuesta correcta –

0

Uso (con nodo actual cualquier profil elemento):

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

Y el código XSLT completa:

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

cuando se aplica en el documento XML proporcionado:

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

produce el, resultado correcto deseada:

<count>0</count> 
<count>1</count> 
<count>1</count> 
Cuestiones relacionadas