2014-12-13 120 views
1

我想获取响应对象的键和值的列表,以便我可以将它们变成散列,但我在理解Nokogiri时遇到问题。该XML:简单的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}" 

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

附加问题: 我该如何将响应分开以便我有类似的情况?

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

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

回答

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元素的子元素:

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

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

解决方案为您提供:

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

关于第二个问题,你基本上问:

  1. 每个foo元素,得到其子元素
  2. 对于每个子元素,打印名称和文字

适合您的解决方案:

> 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}" 
    } 
} 
+0

谢谢,那就是我一直在寻找的! – Rilcon42 2014-12-13 03:58:51

+0

看看你的例子,我试图弄清楚如何将响应彼此分开,但通配符似乎让所有的孩子,不管他们是否在不同的响应标签。有没有办法一次只得到一个响应?可能类似于获得“// Response”,然后通过“// Response/*”循环返回以获得单个响应的元素? – Rilcon42 2014-12-13 05:23:14

+0

@ Rilcon42将您正在尝试做的事添加到您的原始问题中,以便我能够理解您想要的输出内容,并且我会在答案中添加更多内容。 – joelparkerhenderson 2014-12-13 05:46:16