XSLT copy-of如何以当前节点值为动态条件匹配目标节点
问题背景
- 给定如下源XML:
<?xml version="1.0" encoding="utf-8"?> <multimap:Messages xmlns:multimap="http://sap.com/xi/XI/SplitAndMerge"> <multimap:Message1> <INVOIC02> <E1EDP19> <QUALF>003</QUALF> <IDTNR>105</IDTNR> <KTEXT>TEST-1</KTEXT> </E1EDP19> <E1EDP19> <QUALF>003</QUALF> <IDTNR>104</IDTNR> <KTEXT>TEST-2</KTEXT> </E1EDP19> </INVOIC02> </multimap:Message1> <multimap:Message2> <Message2> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <ZZ1_Result> <Material>M2</Material> <ProductStandardID>105</ProductStandardID> <PurchaseOrder>1B</PurchaseOrder> <Supplier>BB</Supplier> </ZZ1_Result> </Message2> </multimap:Message2> </multimap:Messages>
- 需求:为每个
E1EDP19/IDTNR节点匹配对应的ZZ1_Result节点,匹配规则为ZZ1_Result/ProductStandardID的取值与E1EDP19/IDTNR的取值相等。 - 现有硬编码实现的XSLT代码如下:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:sap-com:document:sap:idoc:soap:messages"> <xsl:output method="xml" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- Only match root of IDoc FIDCCP02 --> <xsl:template match="document-node()"> <xsl:apply-templates select="*"/> </xsl:template> <!-- Select all nodes plus attributes --> <xsl:template match="*"> <xsl:element name="{local-name()}"> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> </xsl:template> <!--At E1EDP19(QUALF=003) segment, field IDTNR, try to find a matching PO item from message 2--> <xsl:template match="E1EDP19[QUALF='003']/IDTNR"> <IDTNR> <xsl:value-of select="."/> </IDTNR> <xsl:copy-of copy-namespaces="no" select="//ZZ1_Result[ProductStandardID = '104']"/> </xsl:template> </xsl:stylesheet>
- 硬编码版本运行后,所有IDTNR节点后都固定插入ProductStandardID为104的ZZ1_Result,不符合动态匹配要求,错误运行结果如下:
<?xml version='1.0' encoding='UTF-8' ?> <Messages xmlns="urn:sap-com:document:sap:idoc:soap:messages"> <Message1> <INVOIC02> <E1EDP19> <QUALF>003</QUALF> <IDTNR>105</IDTNR> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <KTEXT>TEST-1</KTEXT> </E1EDP19> <E1EDP19> <QUALF>003</QUALF> <IDTNR>104</IDTNR> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <KTEXT>TEST-2</KTEXT> </E1EDP19> </INVOIC02> </Message1> <Message2> <Message2> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <ZZ1_Result> <Material>M2</Material> <ProductStandardID>105</ProductStandardID> <PurchaseOrder>1B</PurchaseOrder> <Supplier>BB</Supplier> </ZZ1_Result> </Message2> </Message2> </Messages>
- 需要修改的目标代码行如下,要求替换硬编码的
'104'为当前上下文IDTNR的动态值:
<xsl:copy-of copy-namespaces="no" select="//ZZ1_Result[ProductStandardID = '104']" />
- 预期运行结果:
<?xml version='1.0' encoding='UTF-8' ?> <Messages xmlns="urn:sap-com:document:sap:idoc:soap:messages"> <Message1> <INVOIC02> <E1EDP19> <QUALF>003</QUALF> <IDTNR>105</IDTNR> <ZZ1_Result> <Material>M2</Material> <ProductStandardID>105</ProductStandardID> <PurchaseOrder>1B</PurchaseOrder> <Supplier>BB</Supplier> </ZZ1_Result> <KTEXT>TEST-1</KTEXT> </E1EDP19> <E1EDP19> <QUALF>003</QUALF> <IDTNR>104</IDTNR> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <KTEXT>TEST-2</KTEXT> </E1EDP19> </INVOIC02> </Message1> <Message2> <Message2> <ZZ1_Result> <Material>M1</Material> <ProductStandardID>104</ProductStandardID> <PurchaseOrder>1A</PurchaseOrder> <Supplier>AA</Supplier> </ZZ1_Result> <ZZ1_Result> <Material>M2</Material> <ProductStandardID>105</ProductStandardID> <PurchaseOrder>1B</PurchaseOrder> <Supplier>BB</Supplier> </ZZ1_Result> </Message2> </Message2> </Messages>
解决方案
替换动态值不生效的核心原因是XPath的作用域规则:
- 方括号谓词内的
.,指代的是当前正在被筛选的节点(即此处的ZZ1_Result节点),而非模板匹配到的IDTNR上下文节点。如果直接把硬编码的'104'替换为.,判断逻辑会变成「ProductStandardID取值等于ZZ1_Result节点自身的字符串值」,自然无法得到正确匹配结果。 - 要获取当前模板匹配到的IDTNR节点值,需要使用XSLT内置的
current()函数,该函数始终返回当前模板规则绑定的上下文节点,不受XPath谓词内作用域影响。
修改方法
将目标代码行替换为以下内容即可:
<xsl:copy-of copy-namespaces="no" select="//ZZ1_Result[ProductStandardID = current()]" />
XSLT在做节点值比较时会自动提取节点的字符串值做对比,无需额外调用
text()或string()函数取值,直接写current()即可匹配IDTNR节点内的文本值。
修改后运行即可得到预期结果:IDTNR为105时匹配ProductStandardID为105的ZZ1_Result,IDTNR为104时匹配ProductStandardID为104的ZZ1_Result。
内容的提问来源于stack exchange,提问作者user18724535
相关产品推荐
相关产品推荐

