如何通过|连接一个父节点下的子元素XSLT中的分隔符?

时间:2017-12-28 03:54:16

标签: xslt

在连接父元素下的所有子元素时遇到问题。

这是源数据

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<PurchaseOrder id="abc">
    <attr attr-name="A">
        <new-value>123</new-value>
    </attr>
    <attr attr-name="B">
        <new-value>99</new-value>
    </attr>
    <attr attr-name="B">
        <new-value>77</new-value>
    </attr>
    <attr attr-name="C">
        <new-value>1</new-value>
        <new-value>2</new-value>
        <new-value>3</new-value>
        <new-value>4</new-value>
        <new-value>5</new-value>
        <new-value>6</new-value>
        <new-value>7</new-value>
        <new-value>8</new-value>
    </attr>
    <attr attr-name="D">
        <new-value>
            <child1>567</child1>
            <child2>2</child2>
        </new-value>
    </attr>
    <attr attr-name="E">
        <new-value>
            <child3>890</child3>
            <child4>3</child4>
        </new-value>
    </attr>
</PurchaseOrder>

使用XSLT转换

<?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="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">
            <ns0: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:when test="key('keyAttrName', @attr-name)/new-value/materials/material">
                                    <xsl:for-each select="key('keyAttrName', @attr-name)">
                                        <xsl:element name="{$nodeName}">
                                            <xsl:copy-of select="attr" />
                                        </xsl:element>
                                    </xsl:for-each>
                                </xsl:when>
                                <xsl:otherwise>
                            <xsl:for-each select="key('keyAttrName', @attr-name)">
                               <xsl:element name="{$nodeName}">
                                  <xsl:if test="position()!=1">
                                     <ns0:text>|</ns0:text>
                                  </xsl:if>
                                  <xsl:value-of select="."/>
                               </xsl:element>
                            </xsl:for-each>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:for-each>
                    </Order>
                </Orders>
            </ns0:PurchaseOrderMSG>
        </xsl:template>
    </xsl:stylesheet>

预期结果应为

<?xml version="1.0" encoding="UTF-8"?>
<ns0:PurchaseOrderMSG xmlns:ns0="urn:demo:PurchaseOrder">
    <Orders>
        <Order>
            <A>123</A>
            <B>99</B>
            <B>77</B>
            <C>1|2|3|4|5|6|7|8</C>
            <D>
                <child1>567</child1>
                <child2>2</child2>
            </D>
            <E>
                <child3>890</child3>
                <child4>3</child4>
            </E>
        </Order>
    </Orders>
</ns0:PurchaseOrderMSG>

我使用的XSLT附带的输出如下所示。分隔符逻辑不起作用。

<?xml version="1.0" encoding="UTF-8"?>
<ns0:PurchaseOrderMSG xmlns:ns0="urn:demo:PurchaseOrder">
    <Orders>
        <Order>
            <A>123</A>
            <B>99</B>
            <B>77</B>
            <C>12345678</C>
            <D>
                <child1>567</child1>
                <child2>2</child2>
            </D>
            <E>
                <child3>890</child3>
                <child4>3</child4>
            </E>
        </Order>
    </Orders>
</ns0:PurchaseOrderMSG>

我尝试过在一些博客中提到的逻辑,但没有运气

XSLT merging/concatenating values of siblings nodes of same name into single node

Concatenate several child items into one child item using XSLT

1 个答案:

答案 0 :(得分:1)

您需要修改<xsl:otherwise>条件以处理<new-value>节点中的值,如下所示。如果<new-value>个子节点的数量是&gt; 1,然后使用分隔符执行连接,否则只按原样输出值。

<xsl:otherwise>
    <xsl:for-each select="key('keyAttrName', @attr-name)">
        <xsl:element name="{$nodeName}">
            <xsl:choose>
                <xsl:when test="count(new-value) &gt; 1">
                    <xsl:for-each select="new-value">
                        <xsl:value-of select="." />
                        <xsl:if test="position() != last()">
                            <xsl:value-of select="'|'" />
                        </xsl:if>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="." />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:element>
    </xsl:for-each>
</xsl:otherwise>

完整的XSLT和输出如下。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="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">
        <ns0: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:when test="key('keyAttrName', @attr-name)/new-value/materials/material">
                                <xsl:for-each select="key('keyAttrName', @attr-name)">
                                    <xsl:element name="{$nodeName}">
                                        <xsl:copy-of select="attr" />
                                    </xsl:element>
                                </xsl:for-each>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:for-each select="key('keyAttrName', @attr-name)">
                                    <xsl:element name="{$nodeName}">
                                        <xsl:choose>
                                            <xsl:when test="count(new-value) &gt; 1">
                                                <xsl:for-each select="new-value">
                                                    <xsl:value-of select="." />
                                                    <xsl:if test="position() != last()">
                                                        <xsl:value-of select="'|'" />
                                                    </xsl:if>
                                                </xsl:for-each>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                <xsl:value-of select="." />
                                            </xsl:otherwise>
                                        </xsl:choose>
                                    </xsl:element>
                                </xsl:for-each>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </Order>
            </Orders>
        </ns0:PurchaseOrderMSG>
    </xsl:template>
</xsl:stylesheet>

输出

<ns0:PurchaseOrderMSG xmlns:ns0="urn:demo:PurchaseOrder">
    <Orders>
        <Order id="abc">
            <A>123</A>
            <B>99</B>
            <B>77</B>
            <C>1|2|3|4|5|6|7|8</C>
            <D>
                <child1>567</child1>
                <child2>2</child2>
            </D>
            <E>
                <child3>890</child3>
                <child4>3</child4>
            </E>
        </Order>
    </Orders>
</ns0:PurchaseOrderMSG>