如何使用XSLT(内循环问题)转换此XML?

时间:2019-05-06 09:28:22

标签: xml xslt

我有一个不符合我的要求的特定XML输出结构。因此,我正在研究使用XSLT代码将当前结构转换为所需结构的可能性。

我知道我需要一个XSLT变量以及if条件才能完成所需的输出。

这是我当前的XML输入:

<ShipmentInstruction>
        <CarrierCode>AFH</CarrierCode>
        <CarrierProductCode>AFH</CarrierProductCode>
        <ShipmentNoOfBoxes>2</ShipmentNoOfBoxes>
        <Boxes>
          <Box>
            <ShipmentBoxNr>0000000011</ShipmentBoxNr>
            <ShipmentBoxReference>0000000011</ShipmentBoxReference>
            <ShipmentBoxWeight>1.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088824</BarCode>
              </Content>
            </Contents>
          </Box>
          <Box>
            <ShipmentBoxNr>0000000011</ShipmentBoxNr>
            <ShipmentBoxReference>0000000011</ShipmentBoxReference>
            <ShipmentBoxWeight>1.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088831</BarCode>
              </Content>
            </Contents>
          </Box>
          <Box>
            <ShipmentBoxNr>0000000011</ShipmentBoxNr>
            <ShipmentBoxReference>0000000011</ShipmentBoxReference>
            <ShipmentBoxWeight>1.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088848</BarCode>
              </Content>
            </Contents>
          </Box>
          <Box>
            <ShipmentBoxNr>0000000022</ShipmentBoxNr>
            <ShipmentBoxReference>0000000022</ShipmentBoxReference>
            <ShipmentBoxWeight>7.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088572</BarCode>
              </Content>
            </Contents>
          </Box>
          <Box>
            <ShipmentBoxNr>0000000022</ShipmentBoxNr>
            <ShipmentBoxReference>0000000022</ShipmentBoxReference>
            <ShipmentBoxWeight>7.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088589</BarCode>
              </Content>
            </Contents>
          </Box>
        </Boxes>
</ShipmentInstruction>

这是我的必需输出:

<ShipmentInstruction>
        <CarrierCode>AFH</CarrierCode>
        <CarrierProductCode>AFH</CarrierProductCode>
        <ShipmentNoOfBoxes>2</ShipmentNoOfBoxes>
        <Boxes>
          <Box>
            <ShipmentBoxNr>0000000011</ShipmentBoxNr>
            <ShipmentBoxReference>0000000011</ShipmentBoxReference>
            <ShipmentBoxWeight>1.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088824</BarCode>
              </Content>
              <Content>
                <BarCode>8719829088831</BarCode>
              </Content>
              <Content>
                <BarCode>8719829088848</BarCode>
              </Content>
            </Contents>
          </Box>
          <Box>
            <ShipmentBoxNr>0000000022</ShipmentBoxNr>
            <ShipmentBoxReference>0000000022</ShipmentBoxReference>
            <ShipmentBoxWeight>7.5</ShipmentBoxWeight>
            <Contents>
              <Content>
                <BarCode>8719829088572</BarCode>
              </Content>
              <Content>
                <BarCode>8719829088589</BarCode>
              </Content>
            </Contents>
          </Box>
        </Boxes>
      </ShipmentInstruction>

以下是我一直使用的XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
                <xsl:element name="ShipmentInstruction">
                        <xsl:element name="CarrierCode">
                            <xsl:value-of select="//ShipmentInstruction/CarrierCode"/> 
                        </xsl:element>
                        <xsl:element name="CarrierProductCode">
                            <xsl:value-of select="//ShipmentInstruction/CarrierProductCode"/> 
                        </xsl:element>
                        <xsl:element name="ShipmentNoOfBoxes">
                            <xsl:value-of select="//ShipmentInstruction/ShipmentNoOfBoxes"/> 
                        </xsl:element>
                        <xsl:element name="Boxes">
                            <xsl:for-each select="//ShipmentInstruction/Boxes/Box">
                            <xsl:variable name="v1" select="ShipmentBoxNr"/>
                             <xsl:element name="Box">
                             <xsl:variable name="v2" select="ShipmentBoxNr"/>
                                <xsl:element name="ShipmentBoxNr">
                                    <xsl:value-of select="ShipmentBoxNr"/> 
                                </xsl:element>
                                <xsl:element name="ShipmentBoxReference">
                                    <xsl:value-of select="ShipmentBoxReference"/> 
                                </xsl:element>
                                <xsl:element name="ShipmentBoxWeight">
                                    <xsl:value-of select="ShipmentBoxWeight"/> 
                                </xsl:element>
                                    <xsl:element name="Contents">   
                                    <xsl:for-each select="//Contents/Content">
                                        <xsl:element name="Content">
                                            <xsl:element name="Barcode">
                                                <xsl:value-of select="Barcode"/> 
                                            </xsl:element>
                                        </xsl:element>
                                    </xsl:for-each>
                                    </xsl:element>                              
                             </xsl:element>
                            </xsl:for-each>
                        </xsl:element>
                </xsl:element>
    </xsl:template>
</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

似乎您正在使用XSLT 2.0,可以使用for-each-group根据<Content>对元素ShipmentBoxNr进行分组

尝试一下:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">

<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />

<xsl:template match="/">
    <xsl:element name="ShipmentInstruction">
        <xsl:element name="CarrierCode">
            <xsl:value-of select="//ShipmentInstruction/CarrierCode" />
        </xsl:element>
        <xsl:element name="CarrierProductCode">
            <xsl:value-of select="//ShipmentInstruction/CarrierProductCode" />
        </xsl:element>
        <xsl:element name="ShipmentNoOfBoxes">
            <xsl:value-of select="//ShipmentInstruction/ShipmentNoOfBoxes" />
        </xsl:element>
        <xsl:element name="Boxes">
            <xsl:for-each-group select="ShipmentInstruction/Boxes/Box"
                group-by="ShipmentBoxNr">

                <xsl:element name="Box">
                    <xsl:element name="ShipmentBoxNr">
                        <xsl:value-of select="ShipmentBoxNr" />
                    </xsl:element>
                    <xsl:element name="ShipmentBoxReference">
                        <xsl:value-of select="ShipmentBoxReference" />
                    </xsl:element>
                    <xsl:element name="ShipmentBoxWeight">
                        <xsl:value-of select="ShipmentBoxWeight" />
                    </xsl:element>
                    <xsl:element name="Contents">
                        <xsl:for-each-group select="current-group()/Contents/Content" group-starting-with="BarCode">
                            <xsl:copy-of select="current-group()" />
                        </xsl:for-each-group>
                    </xsl:element>
                </xsl:element>
            </xsl:for-each-group>
        </xsl:element>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

在此处查看演示:https://xsltfiddle.liberty-development.net/6r5Gh3v

答案 1 :(得分:1)

或者简单地:

XSLT 2.0

<xsl:stylesheet version="2.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="*"/>

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

<xsl:template match="Boxes">
    <xsl:copy>
        <xsl:for-each-group select="Box" group-by="ShipmentBoxNr">
            <Box>
                <xsl:copy-of select="* except Contents"/>
                <Contents>
                    <xsl:copy-of select="current-group()/Contents/Content"/>
                </Contents>
            </Box>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>