生成一个新树并分配给变量

时间:2010-12-03 11:19:55

标签: xml xslt

我有一个原始的xml文件:

<list>
<no value="8">
    <no value="11">
        <no value="6">
            <no value="32"/>
            <no value="56"/>
        </no>
        <no value="9">
            <no value="111"/>
            <no value="67"/>
        </no>
    </no>
    <no value="7">
        <no value="5"/>
        <no value="11"/>
    </no>
</no>

现在我想交换父节点及其子节点的属性值,例如:

<list>
<no value="8">
    <no value="11">
        <no value="6">
            <no value="32"/>
            <no value="56"/>
        </no>
        <no value="9">
            <no value="111"/>
            <no value="67"/>
        </no>
    </no>
    <no value="11">
        <no value="5"/>
        <no value="7"/>
    </no>
</no>

而且我想将这个树放在一个变量中,该变量将用作另一个模板的输入源。我倾向于使用递归进行交换,直到我获得根的最大值:

<list>
<no value="111">
        <no value="...">
    ......
</no>

有人可以给我一个建议吗?提前谢谢

1 个答案:

答案 0 :(得分:0)

你有一个奇怪的需要...在其他语言中,二元树结构这样的东西与你的算法一起用于订购或获得最大值。这在XSLT中并不是真的需要,因为它只处理树和树,所以它有许多内置算法,如排序。

除此之外,这是我认为你想要转变的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:param name="pReplace"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pReplace" select="$pReplace"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="no[@value][descendant::no/@value]">
        <xsl:param name="pReplace" select="''"/>
        <xsl:variable name="vSwaped"
                      select="descendant-or-self::no
                                 [contains($pReplace,
                                           concat(generate-id(),
                                                  '+'))]"/>
        <xsl:variable name="vPosition" select="count($vSwaped)+1"/>
        <xsl:variable name="vReplace">
            <xsl:for-each
                select="(ancestor::no[$vSwaped]|
                         descendant-or-self::no)[@value]">
                <xsl:sort select="@value"
                          data-type="number" order="descending"/>
                <xsl:if test="position()=$vPosition">
                    <xsl:value-of select="concat(generate-id(),'+',@value)"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:variable>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="value">
                <xsl:value-of select="substring-after($vReplace,'+')"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()">
                <xsl:with-param name="pReplace"
                                select="concat($pReplace,
                                               substring-before($vReplace,'+'),
                                               '+',generate-id(),'|')"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="no[@value][not(descendant::no/@value)]" name="find">
        <xsl:param name="pReplace" select="''"/>
        <xsl:param name="pFind" select="generate-id()"/>
        <xsl:variable name="vFound"
                      select="substring-before(
                                 substring-after(
                                    $pReplace,
                                    concat($pFind,'+')),
                                 '|')"/>
        <xsl:choose>
            <xsl:when test="$vFound!='' and $pFind != $vFound">
                <xsl:call-template name="find">
                    <xsl:with-param name="pReplace" select="$pReplace"/>
                    <xsl:with-param name="pFind" select="$vFound"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates select="@*"/>
                    <xsl:attribute name="value">
                        <xsl:value-of select="//no[generate-id()=$pFind]
                                                  /@value"/>
                    </xsl:attribute>
                    <xsl:apply-templates select="node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

输出:

<list>
    <no value="111">
        <no value="67">
            <no value="56">
                <no value="32"></no>
                <no value="6"></no>
            </no>
            <no value="11">
                <no value="8"></no>
                <no value="9"></no>
            </no>
        </no>
        <no value="11">
            <no value="5"></no>
            <no value="7"></no>
        </no>
    </no>
</list>

解释:父级获取其分支的第N个最大值。 N定义为其分支中已经占用的最大数量加1。如果已从其分支中取得最大值,则祖先也将进入最大计算。最后的叶子遵循替换的路径来找到它们的价值。

这更像是输入状态和输出状态之间的静态映射,除了最后一个叶子。

此外,请注意我正在使用非常一般的模式,因此只有novalue属性元素才会被关注。并且可以存在任何其他类型的元素,它们将被复制。