我有一个看起来像这样的XML:
<?xml version="1.0"?>
<RootName>
<RandomNode v="someValue"/>
<Series>
<Idendity v="C16"/>
<CodeOut v="C41073"/>
<Period>
<TimePeriod v="2013-07-18T22:00Z/2013-07-19T22:00Z"/>
<Resolution v="PT60M"/>
<Interval>
<Pos v="1"/>
<Qty v="14.1"/>
</Interval>
<Interval>
<Pos v="2"/>
<Qty v="20.7"/>
</Interval>
我需要一个xPath来返回符合这些条件的所有 Period
节点:
-
节点
CodeOut
/CodeIn
具有数组中任何值的值 -
此节点
CodeOut
可以命名为CodeOut
或CodeIn
,但只能命名为其中一个 -
TimePeriod
上的日期必须匹配
通过xml重复的唯一节点是 Series
节点 . 换句话说,每个 Series
只有一个 Period
,但是有很多不同的 Series
.
例如,将 Codeout
或 CodeIn
值的所有 Period
节点设为 C41073
或 B85028
,日期为 2013-07-18
.
我尝试使用以下内容匹配多个名称:
//*[@v="C41073"] | //*[@v="B85028"] | ...
但我认为如果只匹配正确的节点会更好,以防其他节点具有相同的值,不是吗?
我正在寻找使用类似“包含”的东西,但它以不同的方式工作 .
我'm using .Net, if that matters, and I' m将在 .SelectNodes()
函数上使用此xPath .
EDIT:
发生了一些奇怪的事情 . 也许语法不正确 . 看看这个测试:
这个: doc.SelectNodes("/*")(0).Name
正在返回 RootName
这个: doc.SelectNodes("/*/*").Count
正在返回 912
这个: doc.SelectNodes("/*/*")(11).Name
正在返回 Series
但是这个: doc.SelectNodes("/RootName").Count
正在返回 0
这个: doc.SelectNodes("/*/Series").Count
正在返回 0
这个: doc.SelectNodes("/*/RootName").Count
正在返回 0
使答案中建议的所有其他xPath序列不起作用 .
编辑:
好吧,这是名称空间,我这样做了:
Dim xmlnsManager As Xml.XmlNamespaceManager = New System.Xml.XmlNamespaceManager(doc.NameTable)
xmlnsManager.AddNamespace("ns", "http://example")
并在xPath序列中的每个元素节点名称前添加 ns:
. (有关它的更多信息,请参见此处:Is it possible to specify the namespace prefix just once in a xpath expression?)
1 回答
要选择仅受
CodeIn
/CodeOut
列表限制的所有Period
元素,您可以执行以下操作:如果您不想将列表中的每个项目列为单独的条件,您可以将它们连接在一起分成一个分隔列表,然后使用
contains
函数,如下所示:请注意,为了避免像
C4
匹配整个值的子字符串(如C41073
)的问题,您需要在属性值之前和之后连接分隔符 . 此外,您需要确保分隔符存在于分隔的值列表的开头和结尾处 . 此外,您选择的分隔符必须是无效字符,该字符在列表中的任何值中都不会出现 .但是,由于它似乎是一个非标准的时间范围值,因此限制它也会有点问题 . 如果开始和结束时间存储在单独的节点中,则会更容易 .
例如,如果你需要做的只是匹配一个确切的
TimePeriod
值,你可以这样做:您可以使用
substring-before(TimePeriod, '/')
和substring-after(TimePeriod, '/')
拆分/
字符上的字符串,但除非使用XPath 2.0,否则无法比较字符串以查看它们是大于还是小于 . 如果您使用的是2.0,则可以使用compare
函数将每个子字符串与搜索值进行比较,但它可能最适合在.NET代码中处理该时间范围比较 .