2

次のような 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>

Periodそして、これらの条件に一致するすべてのノードを返す xPath が必要です。

  • ノードCodeOut/CodeInには、配列にある値のいずれかの値があります
  • このノードにはまたはCodeOutという名前を付けることができますが、これらのうちの 1 つだけです。CodeOutCodeIn
  • の日付TimePeriodは一致する必要があります

xml で繰り返される唯一のノードはSeriesノードです。Periodつまり、ごとに1 つしかありませんSeriesが、さまざまな がたくさんありますSeries

たとえば、 or の値が or であり、日付が であるすべてのノードを取得しPeriodます。CodeoutCodeInC41073B850282013-07-18

次のようなものを使用して、複数の名前を一致させようとしました。

//*[@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")

ns:そして、xPath シーケンス内のすべての要素ノード名の前に追加します。(詳細については、これを参照してください: Is it possible to specify the namespace prefix just once in a xpath expression? )

4

1 に答える 1

1

/リストPeriodだけで制限されたすべての要素を選択するには、次のようにします。CodeInCodeOut

/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']

/と を使用して文字列を分割できますが、XPath 2.0 を使用しsubstring-before(TimePeriod, '/')substring-after(TimePeriod, '/')いない限り、文字列を比較してそれらが大きいか小さいかを確認することはできません。2.0 を使用している場合は、関数を使用してこれらの部分文字列のそれぞれを検索値と比較できますが、compareそれでも面倒です。.NET コードでその時間範囲の比較を処理するのがおそらく最善です。

于 2013-07-18T12:41:46.190 に答える