2

次のような一連の変数タイプがあります。

abc1A, abc1B, abc3B, ...
xyz1A, xyz2A, xyz3C, ...
data1C, data2A, ...

さまざまな xml 形式で保存されます。

<area name="DataMap">
    <int name="number" nullable="true">
        <case var="abc2,abc3,abc5">11</case>
        <case var="abc4,abc6*">8</case>
        <case var="data1,xyz7,xyz8">22</case>
        <case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case>
        <case var="xyz{6,4A,4B,4C}">20</case>
        <case var="other01">15</case>
    </int>
</area>

たとえば、xyz5A のようなインスタンスが何にマップされているかを照会したいと考えています。クエリは 24 を返す必要がありますが、xml ノードでの参照が "xyz4A" のように明示的であるか、"xyz4*" のようなワイルドカードを使用しているか、または上記のような中かっこであるかは事前にわかりません。

これはその行の文字列を照会し、ヒットを正常に返します。

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"xyz")][contains(@var,"5A")]'

しかし、正しくない data5A のヒットも返します。

xpath '/area[@name="DataMap"]/int[@name="number"]/case[contains(@var,"data")][contains(@var,"5A")]'

上記の一貫性のない(ただし、有効だと思います)xmlを解析するxpath/その他のクエリ構造はありますか?明示的な文字列の一致と、ワイルドカードおよび中括弧で囲まれた形式に対してのみクエリを実行できるようです。

4

2 に答える 2

1

あなたの中にbash/perlいることは、おそらくにバインドされていlibxmlます。libxml は XPath 2.0 をサポートしていません。libxml/libxslt と Perl を使用した XPath/XSLT 2.0 に関する SO に関する質問が多数あります。

XPath 1.0 には、さまざまな文字列関数(私が認めざるを得ない小さなもの) があり、それらを積み重ねてみることができます。少し実験しましたが、結果が気に入らなかっただけでなく、考えられるすべてのケースをカバーすることに成功しました。次のような「醜い」構造があります。

...
or
(contains(@var, ',xyz{') and 
 contains(substring-before(substring-after(@var, ',xyz{'), '}'), '5A') and
     (contains(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A,') or
      starts-with(substring-after(@var, ',xyz{'), '5A,') or
      starts-with(substring-after(@var, ',xyz{'), '5A}') or
      substring-after(substring-before(substring-after(@var, ',xyz{'), '}'), ',5A') = ''))

or
...

そして、関数は一致する文字列の最初の出現から機能し、あなたのようなケースを処理するにはs とs のsubstring-*レイヤーがさらに必要であることに気付くでしょう:andor

<case var="data3A,xyz{9},xyz{5A,5B,5C}">24</case>

複数xyz{あり、必要なものが最初のものであることがわかっていない場合。

これは、XML を持っていることを忘れて、Perl が得意とすることだけを行い、それを text として扱う場合だと思います。私は XML 処理とデータ抽出のための XML 対応ツールが好きですが、そのために設計された言語で正規表現と文字列を操作した方がよいでしょう。

于 2012-05-18T15:34:26.957 に答える
0

最も賢い方法は、すべての変数を反復処理し、XPath に要求するのではなく、プログラムで一致を見つけることだと思います。

それを除けば、ブレースについて少なくともいくつかの考えがあります。残念ながら、それらはおそらく質問にはあまり役に立ちません*

.../case[@var =~ /some_regex/]perl XPath の実装では、 、 多分.../case["xyz4A" =~ to_regex(@var)]、そして多分.../case[explode_braces(@var) =~ /(^|,)xyz4A(,|$)/](もちろん適切に書かれたexplode_braces関数を使って)を書くことができるようです。たとえば、http://www.perlmonks.org/?node_id=831612を参照してください。explode_braces私は、最初の方法よりもはるかに簡単に動作する方法を期待しています。また、正規表現をかなり使用しています。繰り返しになりますが、あなたは bash-regex を使用しているようで、それらを perl regex に変換することも比較的簡単なはずです。

それでもうまくいかない場合は、XML パーサーまたはその直前にフックして、中かっこを展開してこの恐ろしい XML 設計を修正してください。

$input =~ s/\bvar="([^"]*)"}/'var="'+explode_braces($2)+'"'/eg;

(または、非常によく似たものです。申し訳ありませんが、ここ数年はあまり perl を書いていません。また、これは、xml が 1 種類の属性引用符のみを使用していることを前提としていますが、これは簡単に修正できvar="、はこれらの属性に含まれており、これはより厳しい制限になる可能性があります。)

于 2012-05-18T18:17:59.697 に答える