Nokogiri的简单XML解析示例

时间:2014-12-13 00:42:41

标签: ruby nokogiri

我正在尝试获取Response对象的键和值列表,以便我可以将它们变成Hash,但是我在理解Nokogiri时遇到了问题。 XML:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
<Response>
    <Name>Anonymous</Name>
    <ExternalDataReference></ExternalDataReference>
    <EmailAddress>hi guys</EmailAddress>
    <IPAddress>blahblah</IPAddress>
    <Status>0</Status>
..... (approximately 30 more elements within each response tag)
</Response>
(approximately 75 more response tags in the document)

我的目标是为每个响应获得类似的内容:

Name: Anonymous
ExternalDataReference:
EmailAddress: hi guys
IPAddress: blahblah

到目前为止我的代码:

f=File.open("./stufftoparse.xml")
doc = Nokogiri::XML(f)
puts "#{doc.xpath("//Response").keys} \n#{doc.xpath("//Response").values}"

我知道上面的代码不起作用,但我不知道如何获取Response标记中的元素(我不认为它们是Response的属性,因为它们在自己的XML中)。有人可以解释如何做到这一点?请注意,我花了一些时间阅读Nokogiri文档,但找不到与XPATH示例有关的内容。

其他问题: 我怎样才能将回复分开,以便我有这样的东西?

Response1:
Name: Anonymous
ExternalDataReference:
EmailAddress: hi guys
IPAddress: blahblah

Response2:
Name: Anonymous
ExternalDataReference:
EmailAddress: hi guys
IPAddress: blahblah

1 个答案:

答案 0 :(得分:2)

如果您逐步尝试,可以更容易看到解决方案。

示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
  <foo>
    <goo>a</goo>
    <hoo>b</hoo>
  </foo>
  <foo>
    <goo>c</goo>
    <hoo>d</hoo>
  </foo>
</xml>

语法//foo选择所有foo元素。

> puts doc.xpath("//foo")
<foo>
  <goo>a</goo>
  <hoo>b</hoo>
</foo>
<foo>
  <goo>c</goo>
  <hoo>d</hoo>
</foo>

Nokogiri以NodeSet的形式返回节点:

> puts doc.xpath("//foo").class
Nokogiri::XML::NodeSet

NodeSet是可枚举的;您可以使用eachmap等方法

> puts doc.xpath("//foo").kind_of?(Enumerable)
true

NodeSet包含两个foo元素:

> doc.xpath("//foo").each{|e| puts e.class }
Nokogiri::XML::Element
Nokogiri::XML::Element

语法//foo/*选择foo元素&#39;子元素:

> puts doc.xpath("//foo/*")
<goo>a</goo>
<hoo>b</hoo>
<goo>c</goo>
<hoo>d</hoo>

要打印元素的信息,请参阅Nokogiri/XML/Node文档;您可能想要的两种方法是nametext

为您解决方案:

> doc.xpath("//foo/*").each{|e|
  puts "#{e.name}:#{e.text}" 
}
goo:a
hoo:b
goo:c
hoo:d

对于你的第二个问题,你基本上要问:

  1. 为每个foo元素,获取其子元素
  2. 为每个子元素打印名称和文本
  3. 为您解决方案:

    > doc.xpath("//foo").each_with_index{|parent_elem, parent_count| 
      puts "Parent #{parent_count + 1}"
      parent_elem.elements.each{|child_elem|
        puts "#{child_elem.name}:#{child_elem.text}"
      }
    }