使用嵌套节点合并多个节点

时间:2011-03-23 13:56:01

标签: xslt

我是XSL中的新手,但是我需要XSL文件将具有相同名称属性的节点合并到一个元素中 - 对于子节点也是如此 - 并且如果有节点'具有不同的名称,则将其放入其中, XML的一个例子如下。

<?xml version="1.0" encoding="UTF-8"?>
<test>
    <component name="root">
        <component name="c2">
            <component name="c3">
                <component name="c4" />
            </component>
        </component>
    </component>
    <component name="root">
        <component name="c2">
            <component name="A4" />
        </component>
        <component name="root">
            <component name="A3" />
        </component>
        <component name="root">
            <component name="X1">
                <component name="X2" />
            </component>
        </component>
    </component>
    <component name="difRoot">
    </component>
</test>

所需的输出如下

<output>
<component name="root">
    <component name="c2">
        <component name="c3">
            <component name="c4"/>
        </component>
        <component name="A4"/>
    </component>
    <component name="A3"/>
          <component name="X1">
                 <component name="X2"/>
          </component>
</component>
<component name="difRoot"/>
</output>

由于

1 个答案:

答案 0 :(得分:2)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kComponentByName" match="component" use="@name"/>
    <xsl:template match="test">
        <output>
            <xsl:call-template name="merge">
                <xsl:with-param name="pSequence" select="*"/>
            </xsl:call-template>
        </output>
    </xsl:template>
    <xsl:template name="merge">
        <xsl:param name="pSequence" select="/.."/>
        <xsl:if test="$pSequence">
            <xsl:variable name="vName" select="$pSequence[1]/@name"/>
            <xsl:for-each select="$pSequence[1]">
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:call-template name="merge">
                        <xsl:with-param name="pSequence"
                             select="key('kComponentByName',$vName)
                                        /component[@name != $vName]"/>
                    </xsl:call-template>
                </xsl:copy>
            </xsl:for-each>
            <xsl:call-template name="merge">
                <xsl:with-param name="pSequence"
                     select="$pSequence[@name != $vName]"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

输出:

<output>
    <component name="root">
        <component name="c2">
            <component name="c3">
                <component name="c4" />
            </component>
            <component name="A4" />
        </component>
        <component name="A3" />
        <component name="X1">
            <component name="X2" />
        </component>
    </component>
    <component name="difRoot" />
</output>

注意:递归层次结构未完全解决,只会阻止自己成为孩子。

更新:命名模板说明:如果pSequence不为空,请取出第一个节点,然后复制自身并将模板应用于所有component元素的子元素相同的@name(过滤那些@name也是如此);最后称自己过滤pSequencecomponent元素与处理过的@name相同{{1}}。因此,它逐级逐级地逐节点过滤兄弟姐妹和孩子。完全圆形预防应该通过一个带有祖先名称的序列进行过滤。这只是运动......