Nokogiri和concat()

时间:2016-12-26 23:29:24

标签: ruby xml xpath nokogiri

如何在Nokogiri xpath表达式中使用concat()?我试过了:

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

但是失败了:

  

ArgumentError:node_set必须是Nokogiri :: XML :: NodeSet

实际上,似乎Nokogiri只接受以“。”开头的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:表达式无效:/ concat('foo',   '酒吧')

我知道Nokogiri基于libxml2,因此它只实现了XPath 1.0。但是concat()是XPath 1.0的一部分。但是,XPath 2.0中的类似函数是string-join(),我给了它一个机会:

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

错误讯息:

  

RuntimeError:xmlXPathCompOpEval:找不到函数字符串连接

请参阅,它与concat()的错误消息不同。所以至少找到了函数concat()。还有一点暗示它可能以某种方式起作用......

xml.xpath("concat()")                                                           

...返回预期的错误消息:

  

Nokogiri :: XML :: XPath :: SyntaxError:参数数量无效:   的concat()

有机会让concat()使用参数吗?

P.S。:像xml.xpath("/root/a/text()")这样的基本xpath表达式可以正常工作。

2 个答案:

答案 0 :(得分:2)

XPath查询通常会返回 node-set ,即文档中的节点集合。在Nokogiri中,这由Nokogiri::XML::NodeSet对象表示。

Nokogiri还允许您使用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 :(得分: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"]

注意,请注意前导.将查询锚定在当前节点。