2

我正在尝试使用 XPath 1.0 从以下 xml 中识别重复的序列号,然后使用 .Net 在 .Net 中对其进行评估XPathNavigator

<?xml version="1.0" encoding="utf-16"?>
<Inventory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Items>
        <Item>
            <SerialNumber>1111</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>1112</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>1112</SerialNumber>
        </Item>
    </Items>
</Inventory>

我试图通过评估来做到这一点

//Items/Item/SerialNumber

.Net中的自定义 XSLT 上下文函数(IXsltContextFunction 像此 MSDN 示例那样实现)中的表达式,但 Invoke 函数一次被调用一个结果,因此我看不到其他结果以查找重复项。

1) 有没有办法使用单个 XPath 1.0 表达式来做到这一点?

或者

2) 有没有办法将元素数组传递到自定义 XSLT 上下文函数类的单个 Invoke 调用中?我在 VB.Net 工作,但对任何人都可以分享的任何 C# 示例都很满意。

谢谢,

加文

编辑

感谢 OR Mapper 和 Dimitre 的回复。我最初接受了 OR Mapper 的回复,因为它确实按照我的要求进行。我已经接受了 Dimitre 的回答,因为我喜欢它提供了一个独特的值列表。不过,这两种回答都非常有帮助!

4

2 回答 2

4

我要回答1),所以2)应该不再重要了:

您可以使用元素preceding-sibling上的轴来查找具有相同序列号的<Item>任何前面的元素。<Item>

试试这个(写成它只返回序列号本身而不是元​​素 - 如果这不是你想要的,并且你不知道如何更改结果,请告诉我):

/Inventory/Items/Item/SerialNumber/node()[.=../../preceding-sibling::Item/SerialNumber/node()]

对于您的示例文档,它返回

1112
于 2012-06-26T08:07:56.087 回答
3

使用

/*/*/Item
      [SerialNumber = following-sibling::Item/SerialNumber
     and
       not(SerialNumber = preceding-sibling::Item/SerialNumber)
      ]

这将为具有相同字符串值的子Item元素的任何一组Item元素选择一个元素。SerialNumber

基于 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:template match="/">
     <xsl:copy-of select=
      "/*/*/Item
          [SerialNumber = following-sibling::Item/SerialNumber
         and
           not(SerialNumber = preceding-sibling::Item/SerialNumber)
          ]"/>
 </xsl:template>
</xsl:stylesheet>

当将此转换应用于此 XML 文档时(基于提供的转换,但更有趣):

<Inventory>
    <Items>
        <Item>
            <SerialNumber>1111</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>2222</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>2222</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>2222</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>1111</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>1111</SerialNumber>
        </Item>
        <Item>
            <SerialNumber>3333</SerialNumber>
        </Item>
    </Items>
</Inventory>

转换计算 XPath 表达式并将所选节点复制到输出:

<Item>
   <SerialNumber>1111</SerialNumber>
</Item>
<Item>
   <SerialNumber>2222</SerialNumber>
</Item>

最后,如果您只想获取SerialNumber重复值,请使用

   /*/*/Item
          [SerialNumber = following-sibling::Item/SerialNumber
         and
           not(SerialNumber = preceding-sibling::Item/SerialNumber)
          ]
           /SerialNumber/text()
于 2012-06-26T13:01:28.897 回答