Как можно перебрать дочерние узлы с определенным именем в XML-фрагменте документа Nokogiri? - PullRequest
8 голосов
/ 18 декабря 2011

Учитывая этот XML в строке с именем "string":

<Guide>
  <Master>
    <Part>12345</Part>
    <Sub>
       <Name>A</Name>
    </Sub>
    <Sub>
       <Name>B</Name>
    </Sub>
  </Master>
  <Master>
    <Part>XYZABC</Part>
    <Sub>
       <Name>A</Name>
    </Sub>
    <Sub>
       <Name>C</Name>
    </Sub>
  </Master>
</Guide>

И в этой строке кода:

bgdoc = Nokogiri::XML::DocumentFragment.parse(xstring.to_xml)

Я хочу просмотреть все узлы с именем "Part"

Я попробовал следующее:

bgdoc.xpath("//Part").each do |node|

и:

bgdoc.children.each do |node|
  next unless node.name=="Part"

Но это не сработало.

Ответы [ 4 ]

8 голосов
/ 18 декабря 2011

Проблема в том, что синтаксический анализ XML как фрагмента возвращает частичный документ XML, т. Е. DocumentFragment, который не имеет корня:

1.9.2-p290 :002 > doc = Nokogiri::XML::DocumentFragment.parse('<a><b>foo</b></a>').root
NoMethodError: undefined method `root' for #<Nokogiri::XML::DocumentFragment:0x00000100b34448>
    from (irb):2
    from /Users/greg/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'

, тогда как полный документ XML имееткорень:

1.9.2-p290 :003 > doc = Nokogiri::XML('<a><b>foo</b></a>').root
 => #<Nokogiri::XML::Element:0x8058b350 name="a" children=[#<Nokogiri::XML::Element:0x80587b10 name="b" children=[#<Nokogiri::XML::Text:0x80587818 "foo">]>]> 

По умолчанию Nokogiri будет искать из корня документа с XPath, подобным //Path:

1.9.2-p290 :004 > doc = Nokogiri::XML('<a><Path>foo</Path></a>').search('//Path')
 => [#<Nokogiri::XML::Element:0x8055465c name="Path" children=[#<Nokogiri::XML::Text:0x805543c8 "foo">]>] 

Но это не удается с фрагментом из-заотсутствующий корень:

1.9.2-p290 :005 > doc = Nokogiri::XML::DocumentFragment.parse('<a><Path>foo</Path></a>').search('//Path')
 => [] 

Хитрость заключается в том, чтобы сказать Нокогири, где искать при работе с фрагментом.Используя относительный поиск или подстановочный знак:

1.9.2-p290 :006 > doc = Nokogiri::XML::DocumentFragment.parse('<a><Path>foo</Path></a>').search('.//Path')
 => [#<Nokogiri::XML::Element:0x8053c69c name="Path" children=[#<Nokogiri::XML::Text:0x8053c46c "foo">]>] 

или

1.9.2-p290 :007 > doc = Nokogiri::XML::DocumentFragment.parse('<a><Path>foo</Path></a>').search('*//Path')
 => [#<Nokogiri::XML::Element:0x8052a208 name="Path" children=[#<Nokogiri::XML::Text:0x80529fec "foo">]>] 
2 голосов
/ 18 декабря 2011
bgdoc = Nokogiri::XML::DocumentFragment.parse(<<EOF)
  <xml stuff>
EOF

bgdoc.xpath(".//Part").each do |node|
  # some instruction
end
1 голос
/ 19 декабря 2011

Если у вас есть только строка, просто выполните синтаксический анализ Nokogiri:XML:

bgdoc = Nokogiri::XML.parse(string)

даст вам рут, из которого вы можете использовать xpath //Part, как вы ожидали.

0 голосов
/ 18 декабря 2011
bgdoc.css("Part")

должен сделать работу.

...