我发现在Xpath表达式中使用“number”函数时,该函数只使用序列中的第一个节点。问题的一个例子:
using System.Xml;
using System;
namespace ConsoleApplication1
{
public class Program
{
public static void Main()
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(
@"<baseball>
<games>
<game>
<id>1</id>
<stadiumId>7</stadiumId>
<attendance>4999</attendance>
</game>
<game>
<id>2</id>
<stadiumId>5</stadiumId>
<attendance>600</attendance>
</game>
<game>
<id>3</id>
<stadiumId>5</stadiumId>
<attendance>789</attendance>
</game>
</games>
<stadiums>
<stadium><id>5</id><capacity>1000</capacity></stadium>
<stadium><id>7</id><capacity>5000</capacity></stadium>
<stadium><id>9</id><capacity>560</capacity></stadium>
</stadiums>
</baseball>");
printNodes("what stadiums had games occur in them?",
doc.SelectNodes("/baseball/stadiums/stadium[./id/text()=/baseball/games/game/stadiumId/text()]"));
printNodes("what stadiums had games occur in them? this time converting to numbers before doing comparison",
doc.SelectNodes("/baseball/stadiums/stadium[number(./id/text())=number(/baseball/games/game/stadiumId/text())]"));
}//Main
private static void printNodes(string description, XmlNodeList nodeList)
{
Console.WriteLine("-----" + description + "-------");
foreach (XmlNode node in nodeList)
Console.WriteLine(node.OuterXml);
Console.WriteLine("-------------------");
}
}//class
}//namespace
输出结果为:
-----what stadiums had games occur in them?-------
<stadium><id>5</id><capacity>1000</capacity></stadium>
<stadium><id>7</id><capacity>5000</capacity></stadium>
-------------------
-----what stadiums had games occur in them? this time converting to numbers before doing comparison-------
<stadium><id>7</id><capacity>5000</capacity></stadium>
-------------------
它仅在第二个输出中返回体育场7的原因(尽管Xpath查询在逻辑上相同)是因为第一个棒球/游戏/游戏节点的stadiumId为7.没有其他游戏节点被评估。
这是数字功能的预期功能吗?有办法解决这个问题吗?
答案 0 :(得分:2)
首先:设计number
仅转换节点集中的第一个元素 - 请参阅number in XPath specification。
第二:
XPath中的=
更像是“任何一对匹配”,而不是“双方都相等”。所以你的第一个陈述是正确的,因为“游戏/游戏”中的元素与“id”匹配“体育场”,第二个不能按预期工作,因为“游戏/游戏/列表” stadiumId“由”number“函数转换的节点变为列表中第一个的ID(见上文)。
如果您要编写许多XPath表达式,请阅读规范,至少是定义“=”如何工作的Booleans部分。
答案 1 :(得分:2)
如果你真的想比较数字,可以在XPath 2.0中使用:
/*/stadiums/*
[xs:integer(id) = /*/games/*/stadiumId/xs:integer(.)]
基于XSLT 2.0的验证:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:sequence select=
"/*/stadiums/*
[xs:integer(id) = /*/games/*/stadiumId/xs:integer(.)]"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<baseball>
<games>
<game>
<id>1</id>
<stadiumId>7</stadiumId>
<attendance>4999</attendance>
</game>
<game>
<id>2</id>
<stadiumId>5</stadiumId>
<attendance>600</attendance>
</game>
<game>
<id>3</id>
<stadiumId>5</stadiumId>
<attendance>789</attendance>
</game>
</games>
<stadiums>
<stadium>
<id>5</id>
<capacity>1000</capacity>
</stadium>
<stadium>
<id>7</id>
<capacity>5000</capacity>
</stadium>
<stadium>
<id>9</id>
<capacity>560</capacity>
</stadium>
</stadiums>
</baseball>
评估XPath表达式并将此评估结果(所选元素)复制到输出:
<stadium>
<id>5</id>
<capacity>1000</capacity>
</stadium>
<stadium>
<id>7</id>
<capacity>5000</capacity>
</stadium>