Как отфильтровать ненужные узлы после узлов с определенным атрибутом?

XML файл:

<a>
  <Item key="1">
    <c1>
      <d11>
      </d11>
      <d12 value="1" />
      <d13 />
    </c1>
  </Item>

  <b2>
    <Item key="fix">
      <d21>
      </d21>
      <d22 value="yes" />
      <d23 />
    </Item>
  </b2>

  <b3>
    <c3>
      <d31>
      </d31>
      <Item key="price">
        <e2 value="no" />
        <e3 />
      </Item>
    </c3>
  </b3>
</a>

Файл .xsl:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
  
<xsl:param name="element-name">Item</xsl:param>
    
<xsl:template match="/">  

    <xsl:for-each select="//*[name()=$element-name]"> 

      <xsl:for-each select="ancestor-or-self::*">

            <xsl:value-of select="name()"/> 

            <xsl:if test="position() != last()">
                <xsl:text>/</xsl:text>
            </xsl:if>
        
            <xsl:if test ="name()=$element-name">
            <xsl:text>[@key='</xsl:text>
            <xsl:value-of select="@key"/>
            <xsl:text>']/</xsl:text>
            </xsl:if>
        </xsl:for-each>    
      
            <xsl:for-each select="descendant::*">

            <xsl:value-of select="name()"/> 

            <xsl:if test="position() != last() and not(@value)">
                <xsl:text>/</xsl:text>
            </xsl:if>
            
            <xsl:if test="(.)[@value]">
                <xsl:text>/@value</xsl:text>
            </xsl:if>
            
            </xsl:for-each> 
      
        <xsl:text>&#10;</xsl:text> 
    </xsl:for-each>   
</xsl:template>

</xsl:stylesheet>

После преобразования хочу получить такие данные:

a/Item[@key='1']/c1/d11/d12/@value
a/b2/Item[@key='fix']/d21/d22/@value
a/b3/c3/Item[@key='price']/e2/@value

Но получились такие данные после трансформации:

a/Item[@key='1']/c1/d11/d12/@valued13
a/b2/Item[@key='fix']/d21/d22/@valued23
a/b3/c3/Item[@key='price']/e2/@valuee3

Как отфильтровать ненужные узлы после узлов с атрибутом @value?


Ответы (1 шт):

Автор решения: Alexander Petrov

Я просто убрал лишний код:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:template match="/">
    <xsl:for-each select="//*[@value]">
      <xsl:for-each select="ancestor-or-self::*">
        <xsl:value-of select="name()"/>
        <xsl:text>/</xsl:text>
      </xsl:for-each>
      <xsl:text>@value&#10;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Результат:

a/Item/c1/d12/@value
a/b2/Item/d22/@value
a/b3/c3/Item/e2/@value

При необходимости, можно вернуть на место код, выводящий атрибут у элемента Item:

<xsl:if test ="name()='Item'">
  <xsl:text>[@key='</xsl:text>
  <xsl:value-of select="@key"/>
  <xsl:text>']/</xsl:text>
</xsl:if>
→ Ссылка