如何通过动态属性值匹配将Article节点迁移至对应OrderLine节点
XML节点迁移通用XSLT实现
需求说明
需要将XML中的Article节点迁移至对应的OrderLine节点,匹配规则为Article的UserArea中DropPoint属性值与OrderLine的LineNumber值一致,无论Article原本归属哪个OrderLine。现有XSLT代码通过固定LineNumber值(如10、20、30)可实现该功能,但因无法预先知晓OrderLine的数量及编号,需修改为无需固定值的通用实现。
源XML示例
<SyncOrder> <DataArea> <Order> <OrderHeader> </OrderHeader> <OrderLine> <LineNumber>10</LineNumber> <Article> <LineNumber>10</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">30</NameValue> </Property> </UserArea> </Article> </OrderLine> <OrderLine> <LineNumber>20</LineNumber> <Article> <LineNumber>20</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> <Article> <LineNumber>30</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> <Article> <LineNumber>50</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> </OrderLine> <OrderLine> <LineNumber>30</LineNumber> <Article> <LineNumber>40</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> </OrderLine> </Order> </DataArea> </SyncOrder>
目标XML示例
<SyncOrder> <DataArea> <Order> <OrderHeader> </OrderHeader> <OrderLine> <LineNumber>10</LineNumber> <Article> <LineNumber>20</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> <Article> <LineNumber>30</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> <Article> <LineNumber>40</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> <Article> <LineNumber>50</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">10</NameValue> </Property> </UserArea> </Article> </OrderLine> <OrderLine> <LineNumber>20</LineNumber> </OrderLine> <OrderLine> <LineNumber>30</LineNumber> <Article> <LineNumber>10</LineNumber> <UserArea> <Property> <NameValue name="DropPoint" type="StringType">30</NameValue> </Property> </UserArea> </Article> </OrderLine> </Order> </DataArea> </SyncOrder>
现有固定值实现代码
<xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="//dns:Order/*:OrderLine/*:Article"> <xsl:element name="{name(.)}" /> </xsl:template> <xsl:template match="//dns:Order/*:OrderLine"> <xsl:if test="./*:LineNumber/text() = '10'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> <xsl:for-each select="/*:SyncOrder/*:DataArea/*:Order/*:OrderLine/*:Article"> <xsl:if test="./*:UserArea/*:Property/*:NameValue[@name='DropPoint']/text() ='10'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> </xsl:copy> </xsl:if> </xsl:for-each> </xsl:copy> </xsl:if> <xsl:if test="./*:LineNumber/text() = '20'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> <xsl:for-each select="/*:SyncOrder/*:DataArea/*:Order/*:OrderLine/*:Article"> <xsl:if test="./*:UserArea/*:Property/*:NameValue[@name='DropPoint']/text() ='20'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> </xsl:copy> </xsl:if> </xsl:for-each> </xsl:copy> </xsl:if> <xsl:if test="./*:LineNumber/text() = '30'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> <xsl:for-each select="/*:SyncOrder/*:DataArea/*:Order/*:OrderLine/*:Article"> <xsl:if test="./*:UserArea/*:Property/*:NameValue[@name='DropPoint']/text() ='30'"> <xsl:copy> <xsl:apply-templates select="node() | @* " /> </xsl:copy> </xsl:if> </xsl:for-each> </xsl:copy> </xsl:if> </xsl:template>
通用版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> <!-- 屏蔽原OrderLine下的Article节点,不输出原节点 --> <xsl:template match="OrderLine/Article"/> <!-- 处理OrderLine节点,添加匹配的Article --> <xsl:template match="OrderLine"> <xsl:copy> <!-- 复制当前OrderLine的原有节点(除了Article) --> <xsl:apply-templates select="@* | node()[not(self::Article)]"/> <!-- 筛选所有Article中DropPoint值等于当前OrderLine的LineNumber的节点 --> <xsl:variable name="currentLineNum" select="LineNumber/text()"/> <xsl:for-each select="/SyncOrder/DataArea/Order/OrderLine/Article"> <xsl:if test="UserArea/Property/NameValue[@name='DropPoint']/text() = $currentLineNum"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:if> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码说明
- 身份模板:保留XML的基本结构,复制所有未被特殊模板匹配的节点和属性。
- 屏蔽原Article节点:通过匹配
OrderLine/Article并不做任何输出,移除原来归属在各个OrderLine下的Article。 - 通用OrderLine处理:
- 复制当前OrderLine的所有原有内容(排除Article)
- 定义变量
currentLineNum获取当前OrderLine的LineNumber值 - 遍历所有Article节点,筛选出DropPoint值与
currentLineNum一致的节点,复制到当前OrderLine下
内容的提问来源于stack exchange,提问作者skater123
相关产品推荐
相关产品推荐

