在C.NET3.5中使用XPath比较不同层次上的两个属性

在C.NET3.5中使用XPath比较不同层次上的两个属性,.net,xpath,comparison,.net,Xpath,Comparison,我有以下XML: <A> <B> <C Since="2011-09-26T11:12:41.1383089Z"> <E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z"/> <E Name="Two" AnotherDate="2011-09-26T11:54:05.7025781Z"/> </C> </

我有以下XML:

<A>
  <B>
     <C Since="2011-09-26T11:12:41.1383089Z">
       <E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z"/>
       <E Name="Two" AnotherDate="2011-09-26T11:54:05.7025781Z"/>
     </C>
  </B>
</A>
但在带有XmlDocument.SelectNodes的.NET 3.5中没有

就我所了解的xpath文档而言,在该版本中.NET支持的xpath 1.0中应该可以进行此查询

我想要达到的目标是: 我想选择所有元素E,它们的另一个日期早于或等于其父元素C的“自”属性

所以:我做错了什么,或者我可以改变什么来实现类似的目标。
请注意,查询也应该在给定的sql where子句中工作。

在我看来,它的行为如下所示:

当两个要比较的对象都不是节点集且运算符为时,则通过将两个对象转换为数字并根据IEEE 754比较数字来比较对象

以及将字符串转换为数字:

由可选空格、可选减号、数字和空格组成的字符串转换为IEEE 754数字,该数字根据IEEE 754四舍五入规则与字符串表示的数学值最接近;任何其他字符串都将转换为NaN

因此,在您的例子中,比较两个NaN,返回false。因此,不会返回任何节点。在XPath2.0中,行为不同,这可能就是它在其他环境中工作的原因

我不认为仅使用XPath1.0就可以选择这样的节点。所以,我认为仅仅使用单个SelectNodes是无法做到这一点的。如果您想使用单个XPath1.0查询来实现这一点,就必须绕过它的限制。看看Dimitre的答案如何做到这一点。

这是非常直截了当的。使用:

基于XSLT的验证:

在提供的XML文档上应用此转换时:

所需的正确结果仅将选定的一个节点复制到输出:


说明:使用标准XPath 1.0函数从日期时间值中删除所有非数字字符,以便将剩余的所有数字字符串作为数字进行正确比较。

如果知道A是根元素,则不要以//开始查询。这不仅会使你的查询速度变慢,还会使它出错。你是对的。但恐怕这不是真正的问题。不过谢谢你的评论。@Stampedev:好问题,+1。这在XPath 1.0中很容易做到,目前您选择了错误的答案:这个答案是错误的。所需的比较可以用单个XPath 1.0表达式表示。@DimitreNovatchev,右。但我觉得这不是一个很好的解决方案。这里的问题是说真话,而不是做出错误的、绝对的陈述,这些陈述会影响盲目接受它们的开发人员。你已经改正了你的答案,这很好。您对XPath 1.0中一般比较运算符的语义的解释也不错。仅供参考,编写XPath表达式不是黑客行为,漂亮的是旁观者的眼睛。编写XPath表达式不是黑客行为。但我认为使用非显而易见的解决方案来克服它的局限性是可行的。函数translate是一个标准的XPath 1.0函数,它正是为解决这些问题而设计的-没有黑客攻击,只是按照预期的方式正常使用。我真的很喜欢这个答案。不知何故它是如此明显,但不知何故它不是!考虑过字符串比较和日期时间比较之后,下一步进行数字比较似乎就要开始了。但事实并非如此:@stampedev:不客气。XPath通常让我们能够轻松优雅地完成看起来几乎不可能的事情。一种美丽而强大的语言,尤其是2.0,更不用说3.0语言了。
//A/B/C/E[@AnotherDate <= ../@Since]
where X.exists(xpathexpression)=1 
  /A/B/C/E
     [not(translate(@AnotherDate, '-:TZ', '')
         >
          translate(../@Since, '-:TZ', '')
          )
      ]
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:template match="/">
     <xsl:copy-of select=
     "/A/B/C/E
         [not(translate(@AnotherDate, '-:TZ', '')
             >
              translate(../@Since, '-:TZ', '')
              )
          ]
     "/>
 </xsl:template>
</xsl:stylesheet>
<A>
    <B>
        <C Since="2011-09-26T11:12:41.1383089Z">
            <E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z"/>
            <E Name="Two" AnotherDate="2011-09-26T11:54:05.7025781Z"/>
        </C>
    </B>
</A>
<E Name="One" AnotherDate="2011-09-26T10:54:05.7025781Z" />