【问题标题】:How do I select unique nodes in XSLT 1.0 using an expression?如何使用表达式在 XSLT 1.0 中选择唯一节点?
【发布时间】:2014-03-10 23:14:02
【问题描述】:

我已经看到了很多关于在 XSLT 中确定唯一节点的问题和解决方案,并成功地让它发挥作用,直到我需要使用表达式来评估唯一性。

使用这个数据文件:

<root>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword1</field></data>
    <data><field>find me: keyword2</field></data>
</root>

还有这个转换模板:

<xsl:template match="/root">
    <xsl:for-each select="data[not(field=preceding-sibling::data/field)]">
        field=<xsl:value-of select="field"/>
    </xsl:for-each>
    <xsl:for-each select="data[not(substring-after(field,': ')=substring-after(preceding-sibling::data/field,': '))]">
        short_field=<xsl:value-of select="substring-after(field,': ')" />
    </xsl:for-each>
</xsl:template>

我得到以下输出:

field=find me: keyword1
field=find me: keyword2
short_field=keyword1
short_field=keyword2
short_field=keyword2
short_field=keyword2

第一个for-each 按预期工作,但是一旦我使用substring-after 处理field(因为实际上前导文本并不总是匹配),只有第一个值实际匹配。注意两个额外的keyword2值。

任何人都可以解释这一点并提出解决方案吗?我正在使用 MSXSL 执行此评估。

【问题讨论】:

  • 您的预期输出是什么?
  • 预期的输出不会有我得到的最后两行。

标签: xslt select unique


【解决方案1】:

我见过很多关于确定唯一性的问题和解决方案 XSLT 中的节点

很遗憾你错过了所有好的 - 即那些与 Muenchian grouping 打交道的人。试试这个方法:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:key name="field-by-suffix" match="field" use="substring-after(.,': ')" />

<xsl:template match="/">
    <xsl:for-each select="root/data/field[count(. | key('field-by-suffix', substring-after(.,': '))[1]) = 1]">
        <xsl:text>short_field=</xsl:text>
        <xsl:value-of select="substring-after(.,': ')" />
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

当应用于以下示例输入时:

<root>
    <data><field>alpha: keyword1</field></data>
    <data><field>bravo: keyword2</field></data>
    <data><field>charlie delta: keyword1</field></data>
    <data><field>echo: keyword2</field></data>
    <data><field>foxtrot: keyword1</field></data>
    <data><field>golf hotel: keyword1</field></data>
    <data><field>echo: keyword2</field></data>
</root>

结果是:

short_field=keyword1
short_field=keyword2

【讨论】:

  • 我见过 Muenchian 的分组方法,通常使用 generate-id。对于我的需求,这些似乎过于复杂。我也见过使用的钥匙,但他们都认为你知道实际的钥匙是什么。您的解决方案完美运行。谢谢!我思考了你的解决方案,我想我理解它是如何工作的。简而言之,您将当前节点与键返回的第一个节点结合起来。如果它们是同一个节点,则只有一个节点,否则将有两个。计数为 1 的结果是具有该键的第一个节点,因此是不同的。
  • @ReeseAnschultz "当前节点与key返回的第一个节点的并集,如果是同一个节点,则只有一个节点" 是。它与 generate-id 的工作方式相同:如果我的 id 与组中第一个成员的 id 相同,那么我就是第一个成员。
【解决方案2】:

如果您查看以下输出:

<xsl:for-each select="data">
    <xsl:value-of select="substring-after(preceding-sibling::data/field,': ')"/>
    <xsl:text>&#10;</xsl:text>
</xsl:for-each>

你会看到在这种情况下它总是得到相同的值。实际上,如果您将第一个字段更改为 keyword0 之类的内容,您将看到在第二个循环中您始终与第一个节点进行比较。另请注意,当数据中有 7 个时,它只输出 6 个值,因为第一个是空的。 substring-after 只处理一个要比较的节点,而不是所有 preceding-sibling:: 节点。

【讨论】:

  • 感谢您的指点。现在对我来说很明显,第一种情况是将节点与生成新节点集的节点集进行比较。第二种情况是比较两个字符串,其中第二种情况与在从第一个节点生成字符串的节点集上调用 string() 等效。这就引出了一个终极问题,我如何比较所有节点的字符串值,而不仅仅是第一个?
  • 下一部分取决于您使用的是 XSLT 1.0 还是 2.0。
猜你喜欢
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-02
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多