解析具有相邻节点的简单 XML-like 字符串

Parsing a simple XML-like string with adjacent nodes

我正在使用 engtagger gem 根据词类对句子进行分类。我得到的输出如下:

puts text
# => "<nnp>My</nnp> <nn>name</nn> <vbz>is</vbz> <nnp>Max</nnp>"

我原以为 gem 会给我一个数组,但我想我必须自己将其强制转换为一个数组。

我最终想要得到的是一个像这样的嵌套数组:

[["My", "nnp"], ["name", "nn"], ["is", "vbz"], ["Max", "nnp"]]

但是我不太确定如何使用 Nokogiri(或其他解析器库)来解决这个问题。这是我尝试过的:

(byebug) doc = Nokogiri::XML(text)
#<Nokogiri::XML::Document:0x3fd400286e78 name="document" children=[#<Nokogiri::XML::Element:0x3fd400286900 name="nnp" children=[#<Nokogiri::XML::Text:0x3fd400286464 "My">]>]>
(byebug) Nokogiri.parse(text)
#<Nokogiri::XML::Document:0x3fd40028cd50 name="document" children=[#<Nokogiri::XML::Element:0x3fd40028c7d8 name="nnp" children=[#<Nokogiri::XML::Text:0x3fd40028c378 "My">]>]>

所以我尝试了两种不同的 Nokogiri 方法,但都只显示第一个节点。我怎样才能得到其余的相邻节点?

或者,如何让 engtagger 调用 return 数组?在文档中,我没有找到如何 return 具有 所有标签 的数组的示例,只有具有一种特定类型标签的数组。

最主要的是格式良好的XML应该有一个根节点。您收到第一个节点只是因为它被视为根节点(也就是说,最顶层)并且当它关闭时,Nokogiri 认为 XML 文档已结束。

Nokogiri::XML("<root>#{text}</root>").
  children.first. # get root node
  children.map { |e| [e.text, e.name] }. # map to what’s needed
  reject { |e| e.last == 'text' } # filter out garbage

过滤可能在语义上更正确:

Nokogiri::XML("<root>#{text}</root>").
  children.first.
  children.reject { |e| Nokogiri::XML::Text === e }.
  map { |e| [e.text, e.name] } 

问题是您错误地解析了片段:

require 'nokogiri'
doc = Nokogiri::XML.fragment("<nnp>My</nnp> <nn>name</nn> <vbz>is</vbz> <nnp>Max</nnp>")
doc.to_xml # => "<nnp>My</nnp> <nn>name</nn> <vbz>is</vbz> <nnp>Max</nnp>"

Nokogiri 想要有效的 XML,但您可以使用 fragment.

让它接受部分 XML 块

那时你可以做:

doc.children.each_with_object([]){ |n, a| a << [n.text, n.name] unless n.text? } 
# => [["My", "nnp"], ["name", "nn"], ["is", "vbz"], ["Max", "nnp"]]