如何使用Ruby解析和打印XML文件

时间:2017-05-16 18:51:25

标签: ruby-on-rails ruby xml xml-parsing nokogiri

我正在尝试使用Ruby解析XML文件。它成功解析,但它不打印我想要打印的内容:

<ssn >
 <p strt="14:13:09" qn="Question 1" stp="14:14:20">
  <v fans="C" id="#00A4DB7F" ans="C" fanst="33.59"/>
  <v fans="A" id="#3910072E" ans="D" fanst="50.71"/>
  <v fans="A" id="#3C44F58D" ans="A" fanst="20.71"/>
  <v fans="B" id="#3C62633D" ans="B" fanst="10.78"/> 
   </p>
  <p strt="14:20:17" qn="Question 2" stp="14:21:24">
  <v fans="A" id="#00A4DB7F" ans="D" fanst="33.59"/>
  <v fans="E" id="#3910072E" ans="C" fanst="50.71"/>
  <v fans="E" id="#3C44F58D" ans="B" fanst="20.71"/>
  <v fans="C" id="#3C62633D" ans="A" fanst="10.78"/> 
    </p>
   <p strt="14:22:17" qn="Question 3" stp="14:23:24">
  <v fans="A" id="#00A4DB7F" ans="A" fanst="33.59"/>
  <v fans="B" id="#3910072E" ans="B" fanst="50.71"/>
  <v fans="C" id="#3C44F58D" ans="C" fanst="20.71"/>
  <v fans="D" id="#3C62633D" ans="D" fanst="10.78"/> 
    </p>
   </ssn>

XML文件的格式为:

Question 1: 
C 
A 
A 
B 

Question 2: 
A 
E 
E
C 

Question 3: 
A 
B 
C 
D

我想打印:

Question 1: 
C 
A 
A 
B 
A 
E 
E
C 
A 
B 
C 
D

Question 2: 
C 
A 
A 
B 
A 
E 
E
C 
A 
B 
C 
D

Question 3: 
C 
A 
A 
B 
A 
E 
E
C 
A 
B 
C 
D

但相反它打印了这个:

$config["base_url"] = base_url() . "search";
$config["per_page"] = 1;
$config["uri_segment"] = 2;

1 个答案:

答案 0 :(得分:1)

问题是你的CSS选择器不是CSS,也不是正确的XPath:

'//ssn//p'
'//ssn//p//v'

Nokogiri在使用它们之前测试它们并认为它们是XPath所以它将它们视为XPath。

要获得你想要的输出我会使用CSS:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<ssn>
  <p qn="Question 1">
    <v ans="C"/>
    <v ans="D"/>
    <v ans="A"/>
    <v ans="B"/> 
  </p>
  <p qn="Question 2">
    <v ans="D"/>
    <v ans="C"/>
    <v ans="B"/>
    <v ans="A"/> 
  </p>
  <p qn="Question 3">
    <v ans="A"/>
    <v ans="B"/>
    <v ans="C"/>
    <v ans="D"/> 
  </p>
</ssn>
EOT

doc.search('p').each { |p|
  puts "#{ p['qn'] }:"
  puts p.search('v').map { |v| v['ans'] }
  puts
}

生成:

Question 1:
C
D
A
B

Question 2:
D
C
B
A

Question 3:
A
B
C
D

您正在使用的XPath选择器的问题是辅助//。在XPath-ese //意味着从文档的顶部开始并在任何地方搜索。因此,//ssn//p表示“从顶部开始查找<ssn>然后从顶部开始查找<p>。相反,您需要//ssn/p,这意味着”从顶部开始查找{ {1}}然后在其中找到<ssn>“。

上面的选择器可以写成:

<p>

会输出同样的东西。

我建议使用CSS,因为它通常会产生更易读的选择器,但有时候我会使用XPath,因为它更强大。

Nokogiri有doc.search('//p').each { |p| puts "#{ p['qn'] }:" puts p.search('./v').map { |v| v['ans'] } puts } search; at相当于at。如果您使用选择器,Nokogiri将尝试确定选择器是否为CSS或XPath。还有CSS和XPath特定方法search('some selector').firstcss类似于xpathsearchat_cssat_xpath版本。根据您得到的输出,Nokogiri似乎只使用at*css变体作为提示,而不是选择器类型的绝对描述。我将不得不在代码中查看以确定。