문제

I'm trying to perform an XSL transformation on the XML below:

<root>
    <row>
        <field1>2014-04-01</field1>
        <field2>AAA123</field2>
        <field3>text1</field3>
        <field4>text1</field4>
        <field5>text1</field5>
    </row>
    <row>
        <field1>2014-04-01</field1>
        <field2>AAA123</field2>
        <field3>text2</field3>
        <field4>text2</field4>
        <field5>text2</field5>
    </row>
    <row>
        <field1>2014-04-01</field1>
        <field2>BBB456</field2>
        <field3>text3</field3>
        <field4>text3</field4>
        <field5>text3</field5>
    </row>
</root>

What I'm trying to do is group <row> elements and their attributes based on a common <field1> and <field2> combination. The output I'm trying to achieve is something like the below:

<output>
    <common>
        <field1>2014-04-01</field1>
        <field2>AAA123</field2>
        <attributes>
            <field3>text1</field3>
            <field4>text1</field4>
            <field5>text1</field5>
        </attributes>
        <attributes>
            <field3>text2</field3>
            <field4>text2</field4>
            <field5>text2</field5>
        </attributes>
    </common>
    <common>
        <field1>2014-04-01</field1>
        <field2>BBB456</field2>
        <attributes>
            <field3>text3</field3>
            <field4>text3</field4>
            <field5>text3</field5>
        </attributes>
    </common>
</output>

I would assume this is done by using some kind of <xsl:for-each> loop, but I'm struggling to find any documentation (or answer on this site) that explains how to build an <xsl:for-each> loop that loops through a combination of nodes/values.

I'm relatively new to XSL and am a little stuck with where to approach this one. If anyone could point me to some documentation or shed any light on how to approach this, that would be greatly appreciated. For info, I'm working with xslt-2.0. Thanks in advance.

도움이 되었습니까?

해결책

Use

<xsl:template match="root">
  <output>
    <xsl:for-each-group select="row" group-by="concat(field1, '|', field2)">
      <common>
       <xsl:copy-of select="field1, field2"/>
       <xsl:apply-templates select="current-group()"/>
     </common>
    </xsl:for-each-group>
  </output>
</xsl:template>

<xsl:template match="row">
  <attributes>
    <xsl:copy-of select="field3, field4, field5"/>
  </attributes>
</xsl:template>

다른 팁

You can use xsl:for-each-group and group by field1 and field2.

Example...

XML Input

<root>
    <row>
        <field1>2014-04-01</field1>
        <field2>AAA123</field2>
        <field3>text1</field3>
        <field4>text1</field4>
        <field5>text1</field5>
    </row>
    <row>
        <field1>2014-04-01</field1>
        <field2>AAA123</field2>
        <field3>text2</field3>
        <field4>text2</field4>
        <field5>text2</field5>
    </row>
    <row>
        <field1>2014-04-01</field1>
        <field2>BBB456</field2>
        <field3>text3</field3>
        <field4>text3</field4>
        <field5>text3</field5>
    </row>
</root>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*">
        <output>
            <xsl:for-each-group select="row" group-by="concat(field1,'|',field2)">
                <common>
                    <xsl:apply-templates select="field1,field2"/>
                    <xsl:apply-templates select="current-group()"/>
                </common>
            </xsl:for-each-group>
        </output>
    </xsl:template>

    <xsl:template match="row">
        <attributes>
            <xsl:apply-templates select="*[not(self::field1) and not(self::field2)]"/>
        </attributes>
    </xsl:template>

</xsl:stylesheet>

XML Output

<output>
   <common>
      <field1>2014-04-01</field1>
      <field2>AAA123</field2>
      <attributes>
         <field3>text1</field3>
         <field4>text1</field4>
         <field5>text1</field5>
      </attributes>
      <attributes>
         <field3>text2</field3>
         <field4>text2</field4>
         <field5>text2</field5>
      </attributes>
   </common>
   <common>
      <field1>2014-04-01</field1>
      <field2>BBB456</field2>
      <attributes>
         <field3>text3</field3>
         <field4>text3</field4>
         <field5>text3</field5>
      </attributes>
   </common>
</output>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top