如何将XML解析为CSV,其中数据仅属于属性

时间:2011-06-21 17:59:24

标签: ruby xml nokogiri text-files

我试图解析的XML文件包含属性中包含的所有数据。我找到了如何构建要插入文本文件的字符串。

我有这个XML文件:

<ig:prescribed_item class_ref="0161-1#01-765557#1">
  <ig:prescribed_property property_ref="0161-1#02-016058#1" is_required="false" combination_allowed="false" one_of_allowed="false">
    <dt:measure_number_type representation_ref="0161-1#04-000005#1">
      <dt:real_type>
        <dt:real_format pattern="\d(1,)\.\d(1,)"/>
      </dt:real_type>
      <dt:prescribed_unit_of_measure UOM_ref="0161-1#05-003260#1"/>
    </dt:measure_number_type>
  </ig:prescribed_property>
  <ig:prescribed_property property_ref="0161-1#02-016059#1" is_required="false" combination_allowed="false" one_of_allowed="false">
    <dt:measure_number_type representation_ref="0161-1#04-000005#1">
      <dt:real_type>
        <dt:real_format pattern="\d(1,)\.\d(1,)"/>
      </dt:real_type>
      <dt:prescribed_unit_of_measure UOM_ref="0161-1#05-003260#1"/>
    </dt:measure_number_type>
  </ig:prescribed_property>
</ig:prescribed_item>
  </ig:identification_guide>

我想将它解析成这样的文本文件,并为每个属性复制类ref:

class_ref|property_ref|is_required|UOM_ref
0161-1#01-765557#1|0161-1#02-016058#1|false|0161-1#05-003260#1
0161-1#01-765557#1|0161-1#02-016059#1|false|0161-1#05-003260#1

这是我到目前为止的代码:

require 'nokogiri'

doc = Nokogiri::XML(File.open("file.xml"), 'UTF-8') do |config|
  config.strict
end

content = doc.xpath("//ig:prescribed_item/@class_ref").map {|i|
  i.search("//ig:prescribed_item/ig:prescribed_property/@property_ref").map { |d| d.text }
}

puts content.inspect

content.each do |c|
  puts c.join('|')
end

2 个答案:

答案 0 :(得分:0)

肯定有基于属性解析的方法。

发动机场文章“Getting started with Nokogiri”有完整的描述。

但很快,他们给出的例子是:

  

匹配具有类的“h3”标签   属性,我们写道:

h3[@class]
  

匹配其类的“h3”标签   attribute等于字符串“r”,   我们写道:

 h3[@class = "r"]
  

使用属性匹配   构造,我们可以修改我们以前的   查询:

 //h3[@class = "r"]/a[@class = "l"]

答案 1 :(得分:0)

我使用CSS访问器简化了一下:

xml = <<EOT
<ig:prescribed_item class_ref="0161-1#01-765557#1">
    <ig:prescribed_property property_ref="0161-1#02-016058#1" is_required="false" combination_allowed="false" one_of_allowed="false">
        <dt:measure_number_type representation_ref="0161-1#04-000005#1">
            <dt:real_type>
                <dt:real_format pattern="\d(1,)\.\d(1,)"/>
            </dt:real_type>
            <dt:prescribed_unit_of_measure UOM_ref="0161-1#05-003260#1"/>
        </dt:measure_number_type>
    </ig:prescribed_property>
    <ig:prescribed_property property_ref="0161-1#02-016059#1" is_required="false" combination_allowed="false" one_of_allowed="false">
        <dt:measure_number_type representation_ref="0161-1#04-000005#1">
            <dt:real_type>
                <dt:real_format pattern="\d(1,)\.\d(1,)"/>
            </dt:real_type>
            <dt:prescribed_unit_of_measure UOM_ref="0161-1#05-003260#1"/>
        </dt:measure_number_type>
    </ig:prescribed_property>
</ig:prescribed_item>
</ig:identification_guide>
EOT

require 'nokogiri'

doc = Nokogiri::XML(xml)

data = [ %w[ class_ref property_ref is_required UOM_ref] ]

doc.css('|prescribed_item').each do |pi|
  pi.css('|prescribed_property').each do |pp|
    data << [
      pi['class_ref'],
      pp['property_ref'],
      pp['is_required'],
      pp.at_css('|prescribed_unit_of_measure')['UOM_ref']
    ]
  end
end

puts data.map{ |row| row.join('|') }

哪个输出:

class_ref|property_ref|is_required|UOM_ref
0161-1#01-765557#1|0161-1#02-016058#1|false|0161-1#05-003260#1
0161-1#01-765557#1|0161-1#02-016059#1|false|0161-1#05-003260#1

  

您能否更详细地解释这一行“pp.at_css('|prescribed_unit_of_measure')['UOM_ref']

在Nokogiri中,有两种类型的“查找节点”方法:“搜索”方法将所有与特定访问者匹配的节点返回为NodeSet,“at”方法返回第一个Node NodeSet的1}},它将是第一个遇到与访问者匹配的节点。

“搜索”方法包括searchcssxpath/。 “at”方法包括atat_cssat_xpath%searchat都接受XPath或CSS访问者。

返回pp.at_css('|prescribed_unit_of_measure')['UOM_ref']:代码pp中的那一点是包含“prescribed_property”节点的局部变量。所以,我告诉代码找到pp下与CSS |prescribed_unit_of_measure访问者匹配的第一个节点,换句话说,<dt:prescribed_unit_of_measure>节点包含的第一个pp标记。当Nokogiri找到该节点时,它返回节点的UOM_ref属性的值。

作为一个FYI,/%运算符在Nokogiri中的别名分别为searchat。它们是其“Hpricot”兼容性的一部分;当Hpricot是首选的XML / HTML解析器时,我们经常使用它们,但对于大多数Nokogiri开发人员来说,它们并不是惯用语。我怀疑这是为了避免与经常使用操作员混淆,至少在我的情况下是这样。

此外,Nokogiri的CSS访问器具有一些特殊的多汁性;它们支持命名空间,就像XPath访问器一样,只有它们使用|。 Nokogiri会让我们忽略命名空间,这就是我所做的。您需要了解有关CSS和名称空间的Nokogiri文档以获取更多信息。