繁体   English   中英

XPath选择匹配的节点

[英]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可以命名为CodeOutCodeIn ,但是其中只有一个
  • TimePeriod上的日期必须匹配

在xml上重复的唯一节点是Series节点。 换句话说,每个Series只有一个Period ,但是有很多不同的Series

例如,获取所有其CodeoutCodeIn值为C41073B85028且日期为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.

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