【问题标题】:How to compare two XML elements from within a xsl:for-loop using XPath如何使用 XPath 比较 xsl:for-loop 中的两个 XML 元素
【发布时间】:2012-03-20 15:18:55
【问题描述】:

我有以下问题:

在样式表文档中,我想从相对简单的 xml 文件创建输出。 虽然大多数常见的 XPath 和 XSLT 东西并不难,但比较两个元素并决定如何继续现在是一个相当大的问题。

示例 xml:

<root>
    <foo>
        <value>1</value>
        <name>foo1</name>
    </foo>
    <foo>
        <value>2</value>
        <name></name>
    </foo>
    <foo>
        <value>3</value>
        <name>foo3</name>
    </foo>

    <bar>
        <value>1</value>
    </bar>
    <bar>
        <value>2</value>
    </bar>
</root>

样式表中有一个 xsl:for 循环,它试图决定是否显示当前节点:

[...]
<xsl:for-each select="bar">
    <xsl:if test="//foo[value=./value]/name">
        <!-- go on, if the content of the 'name' element is not empty -->
    </xsl:if>
</xsl:for-each>
[...]

如果'foo' 中'name' 元素的内容不为空,则使用'value' 元素的平等性,我们的意图只是继续处理这些内容。 结果是,'bar' 中的每一行都会创建一个输出,如果我不打算为第二个条目创建一个事件,因为 '//foo[2]/name' 是空的。

我不确定,目前如何进行......也许生成的密钥就足够了!?我不知道...

感谢您的每一条评论!

【问题讨论】:

  • 我想我所做的不过是再次检查 '//foo/value' 本身,而这很可能最终总是变成“真”。
  • Hm... 在上下文中,我可能使用 'foo' 元素中的 'value' 节点将其与自身进行比较,我尝试使用 "//foo[value=current( )/value]/name" 而不是 "//foo[value=./value]/name" 这可能会奏效,因为不再打印相关行。但如果您有更多建议,请发表评论!
  • 我得出了同样的结论 :-) 请参阅下面的答案。
  • 由于我只是偶尔使用 XSLT/XPath,不幸的是,我的知识有时不足以完成我想要执行的任务......例如:我理解你的方法,但我从来没有想过'xsl:copy-of' 元素的使用。好一个。会努力记住的!

标签: xml xslt xpath


【解决方案1】:

您可能想要使用类似以下的内容:

<xsl:template match="/">
    <root>
        <xsl:for-each select="//bar">
            <xsl:for-each select="//foo[value=current()/value]">
                <xsl:if test="name != ''">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </root>
</xsl:template>

最引人注目的当然是应该使用 current()/value 而不是 ./value,因为 current() 指的是 bar 元素,而 .指的是被循环的 foo 元素。

当应用于提供的输入时,这给出了

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <foo>
        <value>1</value>
        <name>foo1</name>
    </foo>
</root>

【讨论】:

    【解决方案2】:

    使用密钥,例如

    <xsl:key name="k1" match="foo" use="value"/>
    

    作为xsl:stylesheet 的孩子,然后

    <xsl:for-each select="bar[normalize-space(key('k1', value)/name)]">...</xsl:for-each>
    

    【讨论】:

    • 在写这个问题的时候,我想到了这个解决方案,但是由于我的知识不足,我的尝试没有成功,所以我取消了那个并使用了简单的方法,使用 '//foo[value=当前()/值]/名称'。不过还是谢谢你 - 我也在尝试这个!
    • 我刚刚尝试过,它可以正常工作,正如你所建议的那样。我对“xsl:for-each”中的 XPath 查询有点困惑,结果可能是“foo”节点而不是“bar”,但由于查询以“bar”开头,这没什么不仅仅是误会 :-) 非常感谢!
    猜你喜欢
    • 2020-09-14
    • 2022-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多