2016-12-26 9 views
1

Nokogiri xpath式でconcat()を使用するにはどうすればよいですか?私が試した:Nokogiriとconcat()

xml.xpath("concat(/root/a/text(), /root/b/text())") 

しかし、それはで失敗します。

ArgumentError: node_set must be a Nokogiri::XML::NodeSet

鋸山で始まるだけXPath式を受け入れるように実際にそれはそう「」または「/」ので、私はこれらを試してみました:

xml.xpath(".concat(/root/a/text(), /root/b/text())") 
xml.xpath("/concat(/root/a/text(), /root/b/text())") 
xml.xpath("/concat('foo', 'bar')") 

しかし、それらはすべて、このエラーで失敗:

Nokogiri::XML::XPath::SyntaxError: Invalid expression: /concat('foo', 'bar')

私は鋸山はlibxml2のに基づいており、そのように、それが唯一のXPath 1.0を実装して知っています。しかし、concat()はXPath 1.0の一部です。しかし、XPath 2.0の中に同様の機能は、文字列の参加(で)、私はそれにチャンス与えた:

xml.xpath("string-join('foo', 'bar')")  

エラーメッセージ:、それは連結のためのものとは異なるエラーメッセージ

RuntimeError: xmlXPathCompOpEval: function string-join not found

参照ですが()。少なくとも関数concat()は見つかっています。

Nokogiri::XML::XPath::SyntaxError: Invalid number of arguments: concat()

(連結を取得するために、任意のチャンス)の引数での作業:それは何とかうまくいくかもしれないことをもう一つのヒントは

xml.xpath("concat()")               

...予想されるエラーメッセージを返す...ですか?

P.S .: xml.xpath("/root/a/text()")のような基本的なxpath式が正常に動作します。

+1

問題の完全な例を教えてください。 'concat'のXPathは大丈夫ですが、Nokogiriが何か他のことを期待しているところで結果を使用していると思われます。 – matt

答えて

2

アンXPathクエリは、一般ノードセット、文書からのノードのコレクションを返します。ノコギリでは、これはNokogiri::XML::NodeSetオブジェクトで表されます。

ノコギリでは、のxpathメソッドを使用することもできます。この場合、Nokogiri executes the query individually against each of the nodes in the NodeSet in turn, and combines them all into a new NodeSet which it returns as the result。あなたが期待するよう

は、通常、これは、クエリに一致するすべてのノードの組み合わせであることの結果で、動作します。ただし、この場合のように、ノードセット以外のものを返すXPathクエリを使用する場合、これは機能しません。

Nokogiriはクエリを実行した後、新しく作成されたNodeSetに結果(それはNodeSetであることが予想されます)を追加しようとします。結果が実際には文字列this fails with the error you are gettingの場合

これはNokogiri bugに持ち込まれ、roadmapに追加されましたが、まだ解決されていません。

回避策/解決策は、ノードセットではなく、ノードセットですべてのXPathクエリをノードセットではなく単一のノードにすることです。 at_xpathはクエリの最初に一致するノードを返し、そのノードはこの問題なしでさらにxpath呼び出しに使用できます。

1

は、あなたの更新を考えると、私

body = "<root><a>aaa</a><b>bbb</b></root>" 
xml = Nokogiri::XML(body) 
xml.xpath("concat(/root/a/text(), /root/b/text())") # => "aaabbb" 

のために働くように見える、多分これを試してみてください?

body = "<wrapper><root><a>aaa</a><b>bbb</b></root></wrapper>" 
xml = Nokogiri::XML(body) 
xml = xml.xpath("wrapper") # returns a node set 
xml.map { |each| each.xpath("concat(./root/a/text(), ./root/b/text())") } # => ["aaabbb"] 

NBの場合、現在のノードでクエリをアンカーする先行番号.に注目してください。