简体   繁体   English

XPath选择匹配的节点

[英]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节点:

  • The node CodeOut / CodeIn has the value of any of the values that I have in an array 节点CodeOut / CodeIn具有我在数组中拥有的任何值的值
  • This node CodeOut can be named CodeOut or CodeIn , but only one of these 该节点CodeOut可以命名为CodeOutCodeIn ,但是其中只有一个
  • The date on 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 . 例如,获取所有其CodeoutCodeIn值为C41073B85028且日期为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM