[英]XPath to select the nodes that matches
I have a XML that looks like this: 我有一个看起来像这样的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>
And I need a xPath that returns all the Period
nodes which matches these conditions: 我需要一个xPath返回所有符合以下条件的
Period
节点:
CodeOut
/ CodeIn
has the value of any of the values that I have in an array CodeOut
/ CodeIn
具有我在数组中拥有的任何值的值 CodeOut
can be named CodeOut
or CodeIn
, but only one of these CodeOut
可以命名为CodeOut
或CodeIn
,但是其中只有一个 TimePeriod
must match TimePeriod
上的日期必须匹配 The only node that repeates over the xml is the Series
node. 在xml上重复的唯一节点是
Series
节点。 In other words, there is only one Period
per Series
, but there is a lot of different Series
. 换句话说,每个
Series
只有一个Period
,但是有很多不同的Series
。
For example, get all Period
nodes which have his Codeout
or CodeIn
value to being C41073
or B85028
and the date being 2013-07-18
. 例如,获取所有其
Codeout
或CodeIn
值为C41073
或B85028
且日期为2013-07-18
Period
节点。
I tried, to match the multiple names, using something like: 我尝试使用以下方式来匹配多个名称:
//*[@v="C41073"] | //*[@v="B85028"] | ...
But I think it will be better if only matches the correct nodes, just in case some other node has the same value, isn't it? 但是我认为如果只匹配正确的节点会更好,以防万一其他节点具有相同的值,不是吗?
I was searching to use something like "contains", but it works in a different way. 我正在搜索使用“包含”之类的东西,但是它以不同的方式工作。
I'm using .Net, if that matters, and I'm going to use this xPath on the .SelectNodes()
function. 如果这很重要,我将使用.Net,并且将在
.SelectNodes()
函数上使用此xPath。
EDIT: 编辑:
Something strange is happening. 发生了奇怪的事情。 Maybe the syntax is not correct.
语法可能不正确。 Look at this tests:
看一下这个测试:
This: doc.SelectNodes("/*")(0).Name
is returning RootName
这:
doc.SelectNodes("/*")(0).Name
返回RootName
This: doc.SelectNodes("/*/*").Count
is returning 912
这:
doc.SelectNodes("/*/*").Count
返回912
This: doc.SelectNodes("/*/*")(11).Name
is returning Series
这:
doc.SelectNodes("/*/*")(11).Name
名称返回Series
But this: doc.SelectNodes("/RootName").Count
is returning 0
但这是:
doc.SelectNodes("/RootName").Count
返回0
This: doc.SelectNodes("/*/Series").Count
is returning 0
这:
doc.SelectNodes("/*/Series").Count
返回0
And this: doc.SelectNodes("/*/RootName").Count
is returning 0
这是:
doc.SelectNodes("/*/RootName").Count
返回0
Making all the other xPath sequences suggested in answers not working. 使答案中建议的所有其他xPath序列不起作用。
EDIT: 编辑:
Ok, it was the namespace, I did this: 好的,这是名称空间,我这样做:
Dim xmlnsManager As Xml.XmlNamespaceManager = New System.Xml.XmlNamespaceManager(doc.NameTable)
xmlnsManager.AddNamespace("ns", "http://example")
And adding ns:
before every element node name in the xPath sequence. 并在xPath序列中的每个元素节点名称之前添加
ns:
:。 (See this for more information about it: Is it possible to specify the namespace prefix just once in a xpath expression? ) (有关此内容的更多信息,请参见此内容: 是否可以在xpath表达式中仅指定一次名称空间前缀? )
To select all of the Period
elements limited just by the CodeIn
/ CodeOut
list, you could do something like this: 要选择仅受
CodeIn
/ CodeOut
列表限制的所有Period
元素,您可以执行以下操作:
/RootName/Series[(CodeOut/@v = 'C41073') or (CodeOut/@v = 'B85028') or (CodeIn/@v = 'C41073') or (CodeIn/@v = 'B85028')]/Period
If you don't want to list each item in the list as a separate condition, you could concatenate them all together into a delimited list and then use the contains
function, like this: 如果您不想将列表中的每个项目都列为单独的条件,则可以将它们全部连接到一个分隔列表中,然后使用
contains
函数,如下所示:
/RootName/Series[(CodeOut/@v and contains('|C41073|B85028|', concat('|', CodeOut/@v, '|'))) or (CodeIn/@v and contains('|C41073|B85028|', concat('|', CodeIn/@v, '|')))]/Period
Notice, to avoid the problem with a substring like C4
matching the full value, like C41073
, you need to concatenate the delimiter before and after the attribute value. 请注意,为避免像
C4
这样的子字符串匹配完整值(如C41073
,您需要在属性值之前和之后串联定界符。 Also, you need to make sure your delimiter exists at the beginning and ending of the delimited list of values. 另外,您需要确保定界符存在于定界值列表的开头和结尾。 Also, whatever delimiter you choose must be an invalid character which would never occur in any of the values in the list.
另外,无论您选择什么定界符,都必须是一个无效字符,该字符永远不会出现在列表中的任何值中。
However, limiting it also by the TimePeriod
will be a bit more problematic, since it appears to be a non-standard time range value. 但是,通过
TimePeriod
对其进行限制也会带来一些问题,因为它似乎是非标准的时间范围值。 If the start and end times were stored in separate nodes, it would be easier. 如果开始时间和结束时间存储在单独的节点中,那么会更容易。
If all you need to do is match an exact TimePeriod
value, for instance, you could just do something like this: 例如,如果您只需要匹配一个精确的
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']
You can split the string on the /
character, with substring-before(TimePeriod, '/')
and substring-after(TimePeriod, '/')
, but unless you are using XPath 2.0, you can't compare strings to see if they are greater or less than. 您可以使用
substring-before(TimePeriod, '/')
和substring-after(TimePeriod, '/')
在/
字符上分割字符串,但是除非使用XPath 2.0,否则无法比较字符串以查看是否它们大于或小于。 If you are using 2.0, you could compare each of those substrings with the search value using the compare
function, but it's still messy. 如果使用的是2.0,则可以使用
compare
函数将每个子字符串与搜索值进行compare
,但是仍然很混乱。 It's probably best to handle that time-range comparison in your .NET code. 最好在.NET代码中处理该时间范围比较。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.