XSL combining values of siblings if values of an attribute is same

后端 未结 2 1104
没有蜡笔的小新
没有蜡笔的小新 2021-01-16 18:16

This is how my XML looks like







  &         


        
相关标签:
2条回答
  • 2021-01-16 18:37

    This should do it:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
      <xsl:strip-space elements="*" />
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="NodeE">
        <xsl:copy>
          <xsl:apply-templates select="@* | text()" />
          <xsl:call-template name="NextSibling" />
        </xsl:copy>
      </xsl:template>
      <xsl:template match="NodeE[@Name = preceding-sibling::*[1][self::NodeE]/@Name]" />
    
      <xsl:template match="NodeE" mode="includeSib">
        <xsl:value-of select="concat(',', .)"/>
        <xsl:call-template name="NextSibling" />
      </xsl:template>
    
      <xsl:template name="NextSibling">
        <xsl:apply-templates
          select="following-sibling::*[1]
                                      [self::NodeE and @Name = current()/@Name]"
          mode="includeSib" />
      </xsl:template>
    
    </xsl:stylesheet>
    

    When run on this input (with a few additional values to demonstrate its functionality):

    <Nodes>
      <NodeA NodeAattr="123">
    
        <NodeB NodeBattr="456"></NodeB>
    
        <NodeC>
          <NodeD NodeDAttr="ValueD">
            <NodeE Name="ValueABC"> "555" </NodeE >
            <NodeE Name="ValueABC"> "666" </NodeE>
            <NodeE Name="ValueDEF"> "555" </NodeE >
            <NodeE Name="ValueDEF"> "565" </NodeE >
            <NodeE Name="ValueDEF"> "575" </NodeE >
            <NodeE Name="ValueABC"> "595" </NodeE >
          </NodeD>
        </NodeC>
      </NodeA>
    </Nodes>
    

    The result is:

    <Nodes>
      <NodeA NodeAattr="123">
        <NodeB NodeBattr="456" />
        <NodeC>
          <NodeD NodeDAttr="ValueD">
            <NodeE Name="ValueABC"> "555" , "666" </NodeE>
            <NodeE Name="ValueDEF"> "555" , "565" , "575" </NodeE>
            <NodeE Name="ValueABC"> "595" </NodeE>
          </NodeD>
        </NodeC>
      </NodeA>
    </Nodes>
    
    0 讨论(0)
  • 2021-01-16 19:02

    Here's a solution based on my answer to question #825783:

    Stylesheet

    <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:strip-space elements="*"/>
    
      <xsl:key name="kNode" match="NodeE" use="@Name"/>
    
      <!--
      Identity transform: copy elements and attributes from input file as is
      -->
      <xsl:template match="node() | @*">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
      </xsl:template>
    
      <!--
      Use Muenchian grouping to apply unique NodeE elements.
      See http://www.jenitennison.com/xslt/grouping/muenchian.html
      -->
      <xsl:template match="NodeE[generate-id() = 
                           generate-id(key('kNode', @Name)[1])]">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <!--
          Apply <NodeE> elements with the same @Name attribute value as the current
          element with the "concat" mode enabled
          -->
          <xsl:apply-templates select="key('kNode', @Name)" mode="concat"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="NodeE" mode="concat">
        <xsl:value-of select="."/>
        <!-- Add comma except if this is the last node -->
        <xsl:if test="position() != last()">
          <xsl:text>, </xsl:text>
        </xsl:if>
      </xsl:template>
    
      <!-- Drop other <NodeE> elements -->
      <xsl:template match="NodeE"/>
    
    </xsl:stylesheet>
    

    Input

    Using the input provided by JLRishe:

    <Nodes>
      <NodeA NodeAattr="123">
    
        <NodeB NodeBattr="456"></NodeB>
    
        <NodeC>
          <NodeD NodeDAttr="ValueD">
            <NodeE Name="ValueABC"> "555" </NodeE>
            <NodeE Name="ValueABC"> "666" </NodeE>
            <NodeE Name="ValueDEF"> "555" </NodeE>
            <NodeE Name="ValueDEF"> "565" </NodeE>
            <NodeE Name="ValueDEF"> "575" </NodeE>
            <NodeE Name="ValueABC"> "595" </NodeE>
          </NodeD>
        </NodeC>
      </NodeA>
    </Nodes>
    

    Output

    This is different from JLRishe's output because I understood the requirement differently:

    <?xml version="1.0" encoding="utf-8"?>
    <Nodes>
      <NodeA NodeAattr="123">
        <NodeB NodeBattr="456"/>
        <NodeC>
          <NodeD NodeDAttr="ValueD">
            <NodeE Name="ValueABC"> "555" ,  "666" ,  "595" </NodeE>
            <NodeE Name="ValueDEF"> "555" ,  "565" ,  "575" </NodeE>
          </NodeD>
        </NodeC>
      </NodeA>
    </Nodes>
    
    0 讨论(0)
提交回复
热议问题