使用REXML输出标签内容数组?

时间:2014-04-08 19:05:59

标签: ruby xml

以前曾在" REXML - How to extract a single element"但答案并不奏效。显然,text方法已不再可用。

我有一个XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<ice_cream>
    <flavor>Vanilla</flavor>
</ice_cream>

我可以使用REXML将其内容放入数组中:

flavors = xml_file.get_elements('//flavor')

我得到一个数组:

puts flavors[0]

返回:

<flavor>Vanilla</flavor>

相反,我想:

Vanilla

我试过了:

flavors = xml_file.get_elements('//flavor').text

但是,我明白了:

NoMethodError: undefined method `text' for #<Array:0x007fa7a3b94220>

实现这一目标的正确方法是什么?我也愿意使用其他图书馆。

2 个答案:

答案 0 :(得分:1)

使用Nokogiri。你的代码会感谢你。

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<ice_cream>
    <flavor>Vanilla</flavor>
</ice_cream>
EOT

doc.search('flavor') # => [#<Nokogiri::XML::Element:0x3feb8182fc60 name="flavor" children=[#<Nokogiri::XML::Text:0x3feb8182fa44 "Vanilla">]>]
doc.search('flavor').map(&:text) # => ["Vanilla"]

search找到与CSS选择器'flavor'匹配的所有节点,作为NodeSet。

search('flavor').map(&:text)遍历NodeSet并将map方法应用于text方法到每个节点,返回其文本节点。

如果您的XML实际上更复杂:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<ice_cream>
    <flavor>Vanilla</flavor>
    <flavor>Chocolate</flavor>
    <flavor>Strawberry</flavor>
</ice_cream>
EOT

doc.search('flavor') # => [#<Nokogiri::XML::Element:0x3fcc2a577afc name="flavor" children=[#<Nokogiri::XML::Text:0x3fcc2a5778e0 "Vanilla">]>, #<Nokogiri::XML::Element:0x3fcc2a5776c4 name="flavor" children=[#<Nokogiri::XML::Text:0x3fcc2a5774bc "Chocolate">]>, #<Nokogiri::XML::Element:0x3fcc2a5772b4 name="flavor" children=[#<Nokogiri::XML::Text:0x3fcc2a572c78 "Strawberry">]>]
doc.search('flavor').map(&:text) # => ["Vanilla", "Chocolate", "Strawberry"]

或者:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<ice_creams>
  <ice_cream>
      <flavor>Vanilla</flavor>
  </ice_cream>
  <ice_cream>
      <flavor>Chocolate</flavor>
  </ice_cream>
  <ice_cream>
      <flavor>Strawberry</flavor>
  </ice_cream>
</ice_creams>
EOT
ice_cream = doc.search('ice_cream') # => [#<Nokogiri::XML::Element:0x3fe6a91f6b00 name="ice_cream" children=[#<Nokogiri::XML::Text:0x3fe6a91f68f8 "\n      ">, #<Nokogiri::XML::Element:0x3fe6a91f681c name="flavor" children=[#<Nokogiri::XML::Text:0x3fe6a91f6600 "Vanilla">]>, #<Nokogiri::XML::Text:0x3fe6a91f63f8 "\n  ">]>, #<Nokogiri::XML::Element:0x3fe6a91f1de4 name="ice_cream" children=[#<Nokogiri::XML::Text:0x3fe6a91f1bdc "\n      ">, #<Nokogiri::XML::Element:0x3fe6a91f1ac4 name="flavor" children=[#<Nokogiri::XML::Text:0x3fe6a91f1880 "Chocolate">]>, #<Nokogiri::XML::Text:0x3fe6a91f1678 "\n  ">]>, #<Nokogiri::XML::Element:0x3fe6a91f13f8 name="ice_cream" children=[#<Nokogiri::XML::Text:0x3fe6a91f1074 "\n      ">, #<Nokogiri::XML::Element:0x3fe6a91f0e80 name="flavor" children=[#<Nokogiri::XML::Text:0x3fe6a91f0a98 "Strawberry">]>, #<Nokogiri::XML::Text:0x3fe6a91f0840 "\n  ">]>]
ice_cream.search('flavor').map(&:text) # => ["Vanilla", "Chocolate", "Strawberry"]

对于搜索,Nokogiri支持同时使用CSS和XPath选择器,并允许您在方法中使用,如果需要。 search接受CSS和XPath,并且对于CSS或XPath特定方法具有cssxpath的推论。 at返回单个节点,类似于search('some_node').first,分别有at_cssat_xpath

答案 1 :(得分:0)

以下是代码:

require 'rexml/document'

doc = <<-xml
<?xml version="1.0" encoding="UTF-8"?>
<ice_cream>
    <flavor>Vanilla</flavor>
</ice_cream>
xml

xml_doc = REXML::Document.new(doc)
xml_doc.get_elements('//flavor').class # => Array
xml_doc.get_elements('//flavor')[0].class # => REXML::Element
xml_doc.get_elements('//flavor')[0].text # => "Vanilla"

实际上xml_doc.get_elements('//flavor')会为您提供REXML::Element个对象的集合。然后,您需要遍历集合并调用REXML::Element对象上的方法#text来获取文本。