【问题标题】:Selecting unique records in XSLT/XPath在 XSLT/XPath 中选择唯一记录
【发布时间】:2011-03-02 07:25:46
【问题描述】:

我必须在 <xsl:for-each> 循环的上下文中从 XML 文档中仅选择唯一记录。我被 Visual Studio 限制为使用 XSL 1.0

    <availList>
        <item>
          <schDate>2010-06-24</schDate>              
          <schFrmTime>10:00:00</schFrmTime>
          <schToTime>13:00:00</schToTime>
          <variousOtherElements></variousOtherElements>
        </item>
        <item>
          <schDate>2010-06-24</schDate>              
          <schFrmTime>10:00:00</schFrmTime>
          <schToTime>13:00:00</schToTime>
          <variousOtherElements></variousOtherElements>
        </item>
        <item>
          <schDate>2010-06-25</schDate>              
          <schFrmTime>10:00:00</schFrmTime>
          <schToTime>12:00:00</schToTime>
          <variousOtherElements></variousOtherElements>
        </item>
        <item>
          <schDate>2010-06-26</schDate>              
          <schFrmTime>13:00:00</schFrmTime>
          <schToTime>14:00:00</schToTime>
          <variousOtherElements></variousOtherElements>
        </item>
        <item>
          <schDate>2010-06-26</schDate>              
          <schFrmTime>10:00:00</schFrmTime>
          <schToTime>12:00:00</schToTime>
          <variousOtherElements></variousOtherElements>
        </item>
    </availList>

唯一性必须基于三个子元素的值:schDateschFrmTimeschToTime。如果两个item 元素对于所有三个子元素具有相同的值,则它们是重复的。在上述 XML 中,第一项和第二项是重复项。其余的都是独一无二的。如上所述,每个项目都包含我们不希望包含在比较中的其他元素。 “独特性”应该是这三个要素的一个因素,而且只有这些要素。

我已尝试通过以下方式完成此操作:

availList/item[not(schDate = preceding:: schDate and schFrmTime = preceding:: schFrmTime and schToTime = preceding:: schToTime)]

这背后的想法是选择前面没有相同schDateschFrmTimeschToTime 的元素的记录。但是,它的输出缺少最后一项。这是因为我的 XPath 实际上排除了所有子元素值在整个前面的文档中都匹配的项目。没有一个 item 匹配最后一项的所有子元素 - 但由于每个元素的值单独存在于另一个项中,所以最后一项被排除在外。

通过将所有子值作为连接字符串前面每个项目的相同连接值进行比较,我可以获得正确的结果。有人知道我可以这样做吗?

【问题讨论】:

标签: xml xpath transform xslt


【解决方案1】:

我。作为单个 XPath 表达式:

/*/item[normalize-space() and not(. = preceding-sibling::item)]

二。更高效的 (XSLT) 实现,使用键:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kItemByVal" match="item" use="."/>

 <xsl:template match="/">
  <xsl:copy-of select=
   "*/item[generate-id() = generate-id(key('kItemByVal', .))]
   "/>
 </xsl:template>
</xsl:stylesheet>

I 和 II 在应用于提供的 XML 文档时正确选择/复制以下节点

<item><schDate>2010-06-24</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>13:00:00</schToTime></item>
<item><schDate>2010-06-25</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>13:00:00</schFrmTime><schToTime>14:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>

更新:如果&lt;item&gt; 有其他孩子,那么这个转换:

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

    <xsl:key name="kItemBy3Children" match="item"
     use="concat(schDate, '+', schFrmTime, '+', schToTime)"/>

 <xsl:template match="/">
       <xsl:copy-of select=
        "*/item[generate-id()
              = generate-id(key('kItemBy3Children',
                                concat(schDate,
                                       '+', schFrmTime,
                                       '+', schToTime)
                               )
                            )
               ]
        "/>
 </xsl:template>
</xsl:stylesheet>

产生想要的结果

【讨论】:

  • Dimitre,非常感谢您的回答。不过,我担心它对我的情况不起作用-我很抱歉,我在写我的问题时不是很清楚(我随后对其进行了编辑)。问题是,实际上,我的 item 元素还包含各种其他子元素,这些子元素不应该计入是否选择了这些项目。我实际上并不是在寻找“真正的”唯一性,我只是在某些子元素值中寻找唯一性。不过,我相信您的回答对其他人来说很有价值。丹
  • @Daniel-I-S:我已经用修改后问题的解决方案更新了我的答案。
【解决方案2】:

我看到的技术是分两遍完成:按所有三个关键字段对项目进行排序,然后将每个项目与其前一个项目(而不是所有前面的项目)进行比较。

运行两个单独的转换是否可行?它使问题变得容易得多。

我在 Michael Kay's XSLT book 的旧版本中看到了该技术。你可能会在他的一些示例代码中找到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多