在C.NET3.5中使用XPath比较不同层次上的两个属性
我有以下XML:在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> </
<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" />