[英]XPath to select the nodes that matches
我有一个看起来像这样的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
值为C41073
或B85028
且日期为2013-07-18
Period
节点。
我尝试使用以下方式来匹配多个名称:
//*[@v="C41073"] | //*[@v="B85028"] | ...
但是我认为如果只匹配正确的节点会更好,以防万一其他节点具有相同的值,不是吗?
我正在搜索使用“包含”之类的东西,但是它以不同的方式工作。
如果这很重要,我将使用.Net,并且将在.SelectNodes()
函数上使用此xPath。
编辑:
发生了奇怪的事情。 语法可能不正确。 看一下这个测试:
这: 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:
:。 (有关此内容的更多信息,请参见此内容: 是否可以在xpath表达式中仅指定一次名称空间前缀? )
要选择仅受CodeIn
/ CodeOut
列表限制的所有Period
元素,您可以执行以下操作:
/RootName/Series[(CodeOut/@v = 'C41073') or (CodeOut/@v = 'B85028') or (CodeIn/@v = 'C41073') or (CodeIn/@v = 'B85028')]/Period
如果您不想将列表中的每个项目都列为单独的条件,则可以将它们全部连接到一个分隔列表中,然后使用contains
函数,如下所示:
/RootName/Series[(CodeOut/@v and contains('|C41073|B85028|', concat('|', CodeOut/@v, '|'))) or (CodeIn/@v and contains('|C41073|B85028|', concat('|', CodeIn/@v, '|')))]/Period
请注意,为避免像C4
这样的子字符串匹配完整值(如C41073
,您需要在属性值之前和之后串联定界符。 另外,您需要确保定界符存在于定界值列表的开头和结尾。 另外,无论您选择什么定界符,都必须是一个无效字符,该字符永远不会出现在列表中的任何值中。
但是,通过TimePeriod
对其进行限制也会带来一些问题,因为它似乎是非标准的时间范围值。 如果开始时间和结束时间存储在单独的节点中,那么会更容易。
例如,如果您只需要匹配一个精确的TimePeriod
值,则可以执行以下操作:
/RootName/Series[(CodeOut/@v = 'C41073') or (CodeOut/@v = 'B85028') or (CodeIn/@v = 'C41073') or (CodeIn/@v = 'B85028')]/Period[TimePeriod/@v = '2013-07-18T22:00Z/2013-07-19T22:00Z']
您可以使用substring-before(TimePeriod, '/')
和substring-after(TimePeriod, '/')
在/
字符上分割字符串,但是除非使用XPath 2.0,否则无法比较字符串以查看是否它们大于或小于。 如果使用的是2.0,则可以使用compare
函数将每个子字符串与搜索值进行compare
,但是仍然很混乱。 最好在.NET代码中处理该时间范围比较。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.