使用XSLT向父节点创建子元素时遇到困难,因为来自外部源的输入消息的格式有点不同。请求您对XSLT代码提供帮助。如果我可以优化下面复制的现有xslt,也请告诉我。 来自外部来源的输入消息:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<PurchaseOrder id="aoi00037607">
<attr attr-name="A">
<new-value>adi00010210</new-value>
</attr>
<attr attr-name="B">
<new-value>99</new-value>
</attr>
<attr attr-name="C">
<new-value>active</new-value>
</attr>
<attr attr-name="D">
<new-value>
<child1>iop00010538</child1>
<child2>2</child2>
</new-value>
<new-value>
<child1>cid2313213</child1>
<child2>2</child2>
</new-value>
<new-value>
<child1>hri00075562</child1>
<child2>1</child2>
</new-value>
</attr>
<attr attr-name="E">
<new-value>
<child3>spi00010021</child3>
<child4>1</child4>
</new-value>
<new-value>
<child3>vuh000123</child3>
<child4>1</child4>
</new-value>
</attr>
</PurchaseOrder>
为转换而编写的XSLT代码XSLT代码还包括使用|分隔值如果值来自同一来源多次,则为符号。
<?xml version="1.0" encoding="UTF-8"?>
<ns0:stylesheet version="2.0" xmlns:ns0="http://www.w3.org/1999/XSL/Transform">
<ns0:template match="/">
<ns1:PurchaseOrderMSG xmlns:ns1="urn:demo:PurchaseOrder">
<Orders>
<Order>
<ns0:attribute name="id" xmlns:ns0="http://www.w3.org/1999/XSL/Transform">
<ns0:value-of select="/*/@id"/>
</ns0:attribute>
<ns0:call-template name="copy_attr" xmlns:ns0="http://www.w3.org/1999/XSL/Transform">
<ns0:with-param name="Attr_value">A</ns0:with-param>
<ns0:with-param name="New_Attr">A</ns0:with-param>
</ns0:call-template>
<ns0:call-template name="copy_attr" xmlns:ns0="http://www.w3.org/1999/XSL/Transform">
<ns0:with-param name="Attr_value">B</ns0:with-param>
<ns0:with-param name="New_Attr">B</ns0:with-param>
</ns0:call-template>
<ns0:call-template name="copy_attr" xmlns:ns0="http://www.w3.org/1999/XSL/Transform">
<ns0:with-param name="Attr_value">C</ns0:with-param>
<ns0:with-param name="New_Attr">C</ns0:with-param>
</ns0:call-template>
</Order>
</Orders>
</ns1:PurchaseOrderMSG>
</ns0:template>
<ns0:template name="copy_attr">
<ns0:param name="Attr_value"/>
<ns0:param name="New_Attr" select="$Attr_value"/>
<ns0:param name="length" select="100000"/>
<ns0:param name="values">
<ns0:for-each select="//attr[@attr-name = $Attr_value]/new-value">
<ns0:if test="position()!=1">
<ns0:text>|</ns0:text>
</ns0:if>
<ns0:value-of select="."/>
</ns0:for-each>
</ns0:param>
<ns0:element name="{$New_Attr}">
<ns0:value-of select="substring($values,1,number($length))"/>
</ns0:element>
</ns0:template>
</ns0:stylesheet>
我面临着难以编写的代码,将child1 / child2(两个孩子都可以重复多次)字段添加到parentnode D(出现0到无界)和child3 / child4到parentnode E.
预期结果:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:PurchaseOrderMSG xmlns:ns0="urn:demo:PurchaseOrder">
<Orders>
<Order>
<A/>
<B/>
<C/>
<D>
<Child1/>
<Child2/>
</D>
<E>
<Child3/>
<Child4/>
</E>
</Order>
</Orders>
</ns0:PurchaseOrderMSG>
please find the changed input..I have retained old input as well
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<PurchaseOrder id="aoi00037607">
<attr attr-name="A">
<new-value>adi00010210</new-value>
</attr>
<attr attr-name="B">
<new-value>99</new-value>
</attr>
<attr attr-name="B">
<new-value>101</new-value>
</attr>
<attr attr-name="C">
<new-value>active</new-value>
</attr>
<attr attr-name="D">
<new-value>
<child1>iop00010538</child1>
<child2>2</child2>
</new-value>
<new-value>
<child1>cid2313213</child1>
<child2>2</child2>
</new-value>
<new-value>
<child1>hri00075562</child1>
<child2>1</child2>
</new-value>
</attr>
<attr attr-name="E">
<new-value>
<child3>spi00010021</child3>
<child4>1</child4>
</new-value>
<new-value>
<child3>vuh000123</child3>
<child4>1</child4>
</new-value>
</attr>
<attr attr-name="C">
<new-value>inactive</new-value>
</attr>
</PurchaseOrder>
Please find the expected output
<?xml version="1.0" encoding="UTF-8"?>
<ns0:PurchaseOrderMSG xmlns:ns0="urn:demo:PurchaseOrder">
<Orders>
<Order>
<A>adi00010210</A>
<B>99|101</B>
<C>active|inactive</C>
<D>
<Child1>iop00010538</Child1>
<Child2>2</Child2>
</D>
<D>
<child1>cid2313213</child1>
<child2>2</child2>
</D>
<D>
<child1>hri00075562</child1>
<child2>1</child2>
</D>
<E>
<Child3>spi00010021</Child3>
<Child4>1</Child4>
</E>
<E>
<child3>vuh000123</child3>
<child4>1</child4>
</E>
</Order>
</Orders>
</ns0:PurchaseOrderMSG>
答案 0 :(得分:1)
在我们进入解决方案之前,我想建议保留名称空间http://www.w3.org/1999/XSL/Transform
的前缀为xsl
而不是ns0
,因为它被广泛接受并且更容易理解。但它不是强制性的,也不是个人选择。下面的解决方案使用xsl
作为前缀。
首先,我们需要根据attr-name
元素的<attr>
值来准备节点列表。这可以通过在<xsl:for-each>
元素上使用<attr>
并使用attribute value templates {}
作为元素名称来实现。
<xsl:for-each select="attr">
<xsl:element name="{@attr-name}">
....
</xsl:element>
</xsl:for-each>
接下来是对父节点的值进行分组,并使用|
分隔符将它们分开。这可以通过在<xsl:key>
中定义XSLT 1.0
来实现。
<xsl:key name="keyAttrName" match="attr" use="@attr-name" />
如果使用XSLT 2.0
,则可以使用<xsl:for-each-group>
。
<xsl:for-each-group select="attr" group-by="@attr-name">
XSLT 1.0 解决方案
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="urn:demo:PurchaseOrder">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="keyAttrName" match="attr" use="@attr-name" />
<xsl:template match="PurchaseOrder">
<ns1:PurchaseOrderMSG>
<Orders>
<Order id="{@id}">
<xsl:for-each select="attr[generate-id() = generate-id(key('keyAttrName', @attr-name)[1])]">
<xsl:variable name="nodeName" select="@attr-name" />
<xsl:choose>
<xsl:when test="key('keyAttrName', @attr-name)/new-value/*/node()">
<xsl:for-each select="new-value">
<xsl:element name="{$nodeName}">
<xsl:copy-of select="*" />
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$nodeName}">
<xsl:for-each select="key('keyAttrName', @attr-name)">
<xsl:value-of select="new-value" />
<xsl:if test="position() != last()">
<xsl:value-of select="'|'" />
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Order>
</Orders>
</ns1:PurchaseOrderMSG>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0 解决方案
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="urn:demo:PurchaseOrder">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="PurchaseOrder">
<ns1:PurchaseOrderMSG>
<Orders>
<Order id="{@id}">
<xsl:for-each-group select="attr" group-by="@attr-name">
<xsl:choose>
<xsl:when test="current-group()/new-value/*/node()">
<xsl:for-each select="current-group()/new-value">
<xsl:element name="{current-grouping-key()}">
<xsl:copy-of select="*" />
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{current-grouping-key()}">
<xsl:value-of select="current-group()/new-value" separator="|" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</Order>
</Orders>
</ns1:PurchaseOrderMSG>
</xsl:template>
</xsl:stylesheet>
两种解决方案都会在下面显示的输出中转换更新的输入XML。
<ns1:PurchaseOrderMSG xmlns:ns1="urn:demo:PurchaseOrder">
<Orders>
<Order id="aoi00037607">
<A>adi00010210</A>
<B>99|101</B>
<C>active|inactive</C>
<D>
<child1>iop00010538</child1>
<child2>2</child2>
</D>
<D>
<child1>cid2313213</child1>
<child2>2</child2>
</D>
<D>
<child1>hri00075562</child1>
<child2>1</child2>
</D>
<E>
<child3>spi00010021</child3>
<child4>1</child4>
</E>
<E>
<child3>vuh000123</child3>
<child4>1</child4>
</E>
</Order>
</Orders>
</ns1:PurchaseOrderMSG>