在XSL中基于令牌大小提取节点

时间:2013-06-28 11:18:23

标签: xml xslt-1.0 xslt

我是XSL的新手,我正在尝试学习一些东西。假设我有这样的XML:

<?xml version="1.0" encoding="UTF-8"?>
<Result>
    <Node>
        <node-id>1</node-id>
        <node-path>2,3</node-path>
    </Node>
    <Node>
        <node-id>2</node-id>
        <node-path>2,3,4</node-path>
    </Node>
    <Node>
        <node-id>3</node-id>
        <node-path>123,34</node-path>
    </Node>
    <Node>
        <node-id>4</node-id>
        <node-path>2124,14,14</node-path>
    </Node>
    <Node>
        <node-id>5</node-id>
        <node-path>1,0</node-path>
    </Node>
</Result>

我希望得到节点路径字段中只有两个值的所有节点,如:

<?xml version="1.0" encoding="UTF-8"?>
    <Result>
    <Node>
        <node-id>1</node-id>
        <node-path>2,3</node-path>
    </Node>
    <Node>
        <node-id>3</node-id>
        <node-path>123,34</node-path>
    </Node>
    <Node>
        <node-id>5</node-id>
        <node-path>1,0</node-path>
    </Node>
</Result>

我如何在XSL中执行此操作?由于我需要复制节点,我发现我必须使用身份转换作为模板。我还看到我们应该使用递归来计算令牌。我想出了这个:

<?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-nodes">
        <xsl:for-each select="/Result/Node">
            <xsl:variable name="path" select="node-path" />
            <xsl:call-template name="tokenizer" mode="matcher">
                <xsl:with-param name="list" select="$path" />
                <xsl:with-param name="delimiter" select="','" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

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

    <!-- Could not figure out how to write this recursion -->
    <xsl:template name="tokenizer" mode="matcher">
        <xsl:param name="list"/>
        <xsl:param name="delimiter" />
        <xsl:value-of select="substring-before($list,$delimiter)" />
        <xsl:call-template name="tokenizer">
            <xsl:with-param name="list" select="substring-after($list,$delimiter)" />
            <xsl:with-param name="delimiter" select="','" />
        </xsl:call-template>
    </xsl:template>

</xsl:stylesheet>

但是我遇到了递归片的问题。我如何计算令牌并确保只有在计数为2时才进行身份转换?如何修复递归模板?我现有的“tokenizer”模板有什么问题(它甚至没有给我令牌)?任何额外的资源/链接都会非常好。

2 个答案:

答案 0 :(得分:3)

我认为

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">


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

    <xsl:template match="Node[string-length(translate(node-path, ',', '')) != (string-length(node-path) - 1)]"/>


</xsl:stylesheet>

就足够了。

答案 1 :(得分:1)

由于“路径中有两个值的节点”与“路径中只包含一个逗号的节点”相同,因此您可以使用这样的技巧

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

    <!-- ignore Nodes whose node path does not contain one comma -->
    <xsl:template match="Node[translate(node-path, translate(node-path, ',', ''), '') != ',']" />
</xsl:stylesheet>

双翻译技巧是一个很有用的技巧,它提供了一种从字符串中去除所有字符的方法,除了白名单中的字符。在这种情况下,我们将从路径中删除所有非逗号字符,然后检查我们剩下的是否是一个逗号。

相关问题