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