简体   繁体   English

XSLT-检查for-each循环中两个节点是否相等

[英]XSLT - Check if two nodes are equal in a for-each loop

This is my XML: 这是我的XML:

<Shipment>
<AddressData>   
    <Sender>
        <PartnerID>123</PartnerID>
        <Name1>Test</Name1>         
    </Sender>
    <Receiver>
        <PartnerID>124</PartnerID>
        <Name1>Test 2</Name1>       
    </Receiver>
</AddressData>
<Packaging>
    <Package>
        <ID>1</ID>
        <Length>20</Length>
        <Width>20</Width>           
        <PackageType>Carton</PackageType>
    </Package>
    <Package>
        <ID>2</ID>
        <Length>20</Length>
        <Width>20</Width>           
        <PackageType>Carton</PackageType>
    </Package>
</Packaging>
<Items>
    <Item>
        <PackageID>1</PackageID>
        <Partnumber>1234</Partnumber>
        <Quantity>3</Quantity>
    </Item>
    <Item>
        <PackageID>1</PackageID>
        <Partnumber>1235</Partnumber>
        <Quantity>3</Quantity>
    </Item>
    <Item>
        <PackageID>1</PackageID>
        <Partnumber>1236</Partnumber>
        <Quantity>3</Quantity>
    </Item>
    <Item>
        <PackageID>2</PackageID>
        <Partnumber>1232</Partnumber>
        <Quantity>3</Quantity>
    </Item>
    <Item>
        <PackageID>2</PackageID>
        <Partnumber>12322</Partnumber>
        <Quantity>3</Quantity>
    </Item>
</Items>

What I'm trying to acomplish is to list the relevant items of each package directly in the Packaging XML field. 我要完成的工作是直接在Packaging XML字段中列出每个包装的相关项目。

So that I will become the following result: 这样我将成为以下结果:

<Shipment>
<AddressData>
    <Sender>
        <PartnerID>123</PartnerID>
        <Name1>Test</Name1>         
    </Sender>
    <Receiver>
        <PartnerID>124</PartnerID>
        <Name1>Test 2</Name1>       
    </Receiver>
</AddressData>
<Packaging>
    <Package>
        <ID>1</ID>
        <Length>20</Length>
        <Width>20</Width>           
        <PackageType>Carton</PackageType>
        <Items>
            <Item>
                <PackageID>1</PackageID>
                <Partnumber>1234</Partnumber>
                <Quantity>3</Quantity>
            </Item>
            <Item>
                <PackageID>1</PackageID>
                <Partnumber>1235</Partnumber>
                <Quantity>3</Quantity>
            </Item>
            <Item>
                <PackageID>1</PackageID>
                <Partnumber>1236</Partnumber>
                <Quantity>3</Quantity>
            </Item>
        </Items>
    </Package>
    <Package>
        <ID>2</ID>
        <Length>20</Length>
        <Width>20</Width>           
        <PackageType>Carton</PackageType>
        <Items>
            <Item>
                <PackageID>2</PackageID>
                <Partnumber>1232</Partnumber>
                <Quantity>3</Quantity>
            </Item>
            <Item>
                <PackageID>2</PackageID>
                <Partnumber>12322</Partnumber>
                <Quantity>3</Quantity>
            </Item>
        </Items>
    </Package>
</Packaging>

</Shipment>

What I've tried to do is the following XSLT Tranformation: 我尝试做的是以下XSLT转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="Items">
</xsl:template>

<xsl:template match="Packaging">
    <Packaging>
        <xsl:for-each select="Package">
            <ID>
                <xsl:value-of select="ID"/>
            </ID>
            <Length>
                <xsl:value-of select="Length"/>
            </Length>
            <Width>
                <xsl:value-of select="Width"/>
            </Width>
            <PackageType>
                <xsl:value-of select="PackageType"/>
            </PackageType>
            <Items>
                <xsl:for-each select="../../Items/Item">
                    <xsl:if test="PackageID = ../../Packaging/Package/ID">
                    <Item>
                        <PackageID><xsl:value-of select="PackageID"/></PackageID>
                        <Partnumber><xsl:value-of select="Partnumber"/></Partnumber>
                        <Quantity><xsl:value-of select="Quantity"/></Quantity>
                    </Item>
                    </xsl:if>
                </xsl:for-each>
            </Items>
        </xsl:for-each>
    </Packaging>
</xsl:template>
</xsl:stylesheet>

My current XSLT Transformation isn't working because all Items regardless of the ID will be shown. 我当前的XSLT转换不起作用,因为将显示所有项目,无论ID如何。 So the if statement seems to be not working correctly. 因此,if语句似乎无法正常工作。

Thanks 谢谢

The issue is that as soon as you do xsl:for-each select="../../Items/Item" you are in a different context, and your previous context (of the Package) is effectively "forgotten". 问题是,一旦执行xsl:for-each select="../../Items/Item"您就处于不同的上下文中,并且(包装)的先前上下文实际上被“遗忘了”。

What you can do is store the current package id in a variable before selecting the items, and use that in the compate 您可以做的是在选择商品之前将当前包裹ID存储在变量中,然后在组合中使用

<Items>
    <xsl:variable name="packageId" select="ID" />
    <xsl:for-each select="../../Items/Item">
        <xsl:if test="PackageID = $packageId">
        <Item>
            <PackageID><xsl:value-of select="PackageID"/></PackageID>
            <Partnumber><xsl:value-of select="Partnumber"/></Partnumber>
            <Quantity><xsl:value-of select="Quantity"/></Quantity>
        </Item>
        </xsl:if>
    </xsl:for-each>
</Items>

In fact, you can put your condition in the select of the xsl:for-each rather than do an xsl:if 实际上,您可以将条件放在xsl:for-each的选择中,而不是xsl:if

<xsl:variable name="packageId" select="ID" />
<xsl:for-each select="../../Items/Item[PackageID = $packageId]">

In this case, this condition could reference the current package node, with current() 在这种情况下,此条件可以使用current()引用当前包节点

<xsl:for-each select="../../Items/Item[PackageID = current()/ID]">

But having said that, it may be even better to use xsl:key here. 话虽如此,在这里使用xsl:key可能更好。 Define a key like so (as a child of xsl:stylesheet ) 像这样定义一个键(作为xsl:stylesheet

<xsl:key name="items" match="Item" use="PackageID" />

Then, you can do this... 然后,您可以执行此操作...

<xsl:for-each select="key('items', ID)">

In fact, you don't even need xsl:for-each here at all. 实际上,您甚至根本不需要xsl:for-each Use xsl:apply-templates and take advantage of the identity template. 使用xsl:apply-templates并利用身份模板。

Try this simplified XSLT: 试试这个简化的XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="items" match="Item" use="PackageID" />

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

<xsl:template match="Items" />

<xsl:template match="Package">
    <Package>
        <xsl:apply-templates />
        <Items>
          <xsl:apply-templates select="key('items', ID)" />
        </Items>
    </Package>
</xsl:template>
</xsl:stylesheet>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM