0

我有这个 XML 。

<?xml version="1.0" encoding="UTF-8"?>

<Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNameSpaceschemaLocation="browsenode.xsd">

    <Node>
        <node-id>1</node-id>
        <children count="2">
            <id> 2 </id>
            <id> 3 </id>
        </children>
    </Node>
    <Node>
        <node-id>2</node-id>
        <children count="1">
            <id> 4 </id>
        </children>
    </Node>
    <Node>
        <node-id>3</node-id>
        <children count="0">

        </children>
    </Node>
    <Node>
        <node-id>4</node-id>
        <children count="0">

        </children>
    </Node>
    <Node> 
        <node-id>5</node-id>
        <children count="0">

        </children>
    </Node>  
</Result>

我想把它变成

<?xml version="1.0" encoding="UTF-8"?>

<Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNameSpaceschemaLocation="browsenode.xsd">

    <Node>
        <node-id>1</node-id>
        <children count="2">
            <id> 2 </id>
            <id> 3 </id>
        </children>
    </Node>
    <Node>
        <node-id>2</node-id>
        <children count="1">
            <id> 4 </id>
        </children>
    </Node>
    <Node>
        <node-id>3</node-id>
        <children count="0">

        </children>
    </Node>
    <Node>
        <node-id>4</node-id>
        <children count="0">

        </children>
    </Node>
</Result>

即..给定一个节点ID,我想要所有可以从 i 到达的节点。顶部 XML 是树的扁平化版本。

我试着用这个 XSLT 来做。

    <?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:template name="root-matcher" match="/">
        <Result>
            <query>
                Query String
            </query>
        <xsl:call-template name="matcher">
            <xsl:with-param name="nodeValue" select="'1'" />
        </xsl:call-template>
        </Result>
    </xsl:template>

    <xsl:template name="matcher">
        <xsl:param name="nodeValue" />
        <xsl:if test="/Result/Node/node-id[text()=$nodeValue]">
            <Node>
                <browseNodeId>
                    <xsl:value-of select="/Result/Node/node-id" />
                </browseNodeId>
                <children>
                    <xsl:for-each select="/Result/Node/children/id">
                        <id>
                            <xsl:value-of select="." />
                        </id>
                    </xsl:for-each> 
                </children>
            </Node>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

有了这个,我只能达到一个层次。1.我如何递归地做到这一点?

我尝试在匹配器模板之后添加,但它不起作用。

  1. 如何通过 XSLT 获得 children="2" 或 children="0" 属性?

我对 XSLT 非常陌生。事实上,我今天开始了它并试图理解。如果问题很幼稚,请原谅。欢迎任何资源/建议。好心提醒

4

1 回答 1

2

您请求的输出与您的 xslt 不匹配。我的理解是,您希望<Node>输出中只有节点()可以通过子 ID 访问,形成一个统计节点。

根据您的 xlst,您可以尝试以下操作:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

    <xsl:template name="root-matcher" match="/">
        <Result >
            <query>
                Query String
            </query>
            <xsl:call-template name="matcher">
                <xsl:with-param name="nodeValue" select="'1'" />
            </xsl:call-template>

        </Result>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="matcher">
        <xsl:param name="nodeValue" />
        <xsl:apply-templates select="//Node[node-id=$nodeValue]" mode="matcher" />
    </xsl:template>

    <xsl:template match="Node" mode="matcher">
        <xsl:copy>
            <xsl:apply-templates  />
        </xsl:copy>
        <xsl:for-each select="children/id">
            <xsl:apply-templates select="//Node[node-id=normalize-space(current()/.)]" mode="matcher" />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

即使不需要获得请求的输出,我也保留了根匹配和命名模板“匹配器”。

这将产生以下输出:

<Result>
    <query>
        Query String
    </query>
    <Node>
        <node-id>1</node-id>
        <children count="2">
            <id> 2 </id>
            <id> 3 </id>
        </children>
    </Node>
    <Node>
        <node-id>2</node-id>
        <children count="1">
            <id> 4 </id>
        </children>
    </Node>
    <Node>
        <node-id>4</node-id>
        <children count="0">

        </children>
    </Node>
    <Node>
        <node-id>3</node-id>
        <children count="0">

        </children>
    </Node>
</Result>

一些解释:
<xsl:template match="@*|node()">这是一种递归 标识转换,是最基本的 xslt 设计技术之一。使用喜爱的 to
也是一个好习惯。 apply-templatesfor-each

<xsl:apply-templates select="//Node[node-id=$nodeValue]" mode="matcher" /> 这将查找文档中符合条件 ( [node-id=$nodeValue]) 的所有 Node 元素:其中 node-id 的值与变量 nodeValue 中的值相同。

这里不需要使用模式。这使得模板可以匹配相同的节点,但根据使用的模式表单调用者行为不同。

<xsl:apply-templates select="//Node[node-id=normalize-space(current()/.)]" mode="matcher" />这是对具有与当前子节点相同 id 的节点的节点模板的递归调用。

看看:w3.org

于 2013-06-12T15:36:34.700 回答