2

我是新手 Ruby 程序员,刚刚获得了转换巨大 XML 并将其保存到单独的 JSON 文件的新任务。例如:

<listing>
  <id>abc12345</id>
  <name>BCD</name>
  <address>12 Main St</address>
</listing>

<listing>
  <id>a1b2c3d4</id>
  <name>XYZ</name>
  <address>14 Main St</address>
</listing>

<listing>
  <id>bcde45678</id>
  <name>MNO</name>
  <address>14 Broadway</address>
</listing>

我想将它保存到单独的文件中,并在此示例中使用 id 作为文件名将是 abc12345.json、a1b2c3d4.json 和 bcde45678.json,其中每个都包含如下内容:

    {
  "listing": {
    "id": "bcde45678",
    "name": "MNO",
    "address": "14 Broadway"
  }
}

有没有人可以帮我解决这个问题。对于所有未来的帮助,我真的很感激

4

2 回答 2

2

我假设您想将列表块作为 JSON 打印到单个文件中。如果您可以访问“active_support/core_ext”和“nokogiri”,并且不太关心如何将 XML 转换为 JSON,则可以这样做:

require 'active_support/core_ext'
require 'nokogiri'

xml = Nokogiri::XML(File.read "yourfile")

xml.search("//listing").each do |l|
  filename = l.at_xpath("id").content
  File.open(filename + '.json', 'w') do |file|
    file.print Hash.from_xml(l.to_xml).to_json
  end
end
于 2013-06-20T20:40:57.093 回答
0

这是使用XMLSimple(或不使用,这是您的毒药)和使用 JSON 的核心模块扩展的好案例:

require 'json/add/core'
require 'xmlsimple'

xml_files = [
'<listing>
  <id>abc12345</id>
  <name>BCD</name>
  <address>12 Main St</address>
</listing>',
'<listing>
  <id>a1b2c3d4</id>
  <name>XYZ</name>
  <address>14 Main St</address>
</listing>',
'<listing>
  <id>bcde45678</id>
  <name>MNO</name>
  <address>14 Broadway</address>
</listing>'
]

xml_files.each do |xml|
  obj = XmlSimple.xml_in(xml, :ForceArray => false)
  File.write(obj['id'] + '.json', JSON.pretty_generate(obj))
end

这会创建三个文件:

a1b2c3d4.json:

{
  "id": "a1b2c3d4",
  "name": "XYZ",
  "address": "14 Main St"
}

abc12345.json:

{
  "id": "abc12345",
  "name": "BCD",
  "address": "12 Main St"
}

bcde45678.json:

{
  "id": "bcde45678",
  "name": "MNO",
  "address": "14 Broadway"
}

我怀疑 XMLSimple 是基于 Perl 的 XMLSimple,它读取 XML 文件并将其转换为本地对象。在这种情况下,它将创建 XML 的散列,从而可以<id>像普通散列键一样轻松访问标记的内容。XMLSimple 在将传入的 XML 解析为对象时具有并且需要很大的灵活性,因此我使用标志对其进行了微调:ForceArray => false,这在为散列键创建值时为代码提供了一些宽容。您需要花一些时间浏览文档以了解它的选项。

JSON.pretty_generate(obj)创建格式良好的输出。这会使文件大小膨胀,但是如果您有必须阅读这些文件的人,那也没关系。如果没有,则使用obj.to_json生成更紧凑的输出,这将减少读取 JSON 文件时的 I/O 时间。

这负责编写 XML 的各个块。

你没有说“巨大”是什么意思。在我的世界里,巨大的文件可以是多 GB 的文件,甚至可以达到两位数。对于非常大的 XML 文件,我建议研究使用 Nokogiri::SAX 来使用流处理并生成类似于您的示例 XML 的小型 XML 文件。然后你可以使用上面的代码迭代那些。

如果文件不是很大,只是很大,让 Nokogiri 将整个文件解析为 DOM 并遍历<listing>节点,然后将它们输出到文件中。您提供的示例 XML 对于真正的 XML 文件无效,因为它缺少包含节点,因此,基于“固定”版本:

require 'json/add/core'
require 'nokogiri'
require 'xmlsimple'

xml_files =<<EOT
<xml_root>
  <listing>
    <id>abc12345</id>
    <name>BCD</name>
    <address>12 Main St</address>
  </listing>
  <listing>
    <id>a1b2c3d4</id>
    <name>XYZ</name>
    <address>14 Main St</address>
  </listing>
  <listing>
    <id>bcde45678</id>
    <name>MNO</name>
    <address>14 Broadway</address>
  </listing>
</xml_root>
EOT

doc = Nokogiri::XML(xml_files)

xml_files = []
doc.search('listing').each do |listing|
  xml_file = listing.at('id').text + '.xml'
  xml_files << xml_file
  File.write(xml_file, listing.to_xml)
end

xml_files.each do |file|
  obj = XmlSimple.xml_in(File.read(file), :ForceArray => false)
  File.write(obj['id'] + '.json', JSON.pretty_generate(obj))
end

运行后,这些文件存在,并且JSON文件的内容与对应的XML文件相关联:

a1b2c3d4.json  a1b2c3d4.xml   abc12345.json  abc12345.xml   bcde45678.json bcde45678.xml

对于简单的 XML,您可以省去 XMLSimple,但对于大型 XML 块,以下可能会有点麻烦,但是,至少您可以选择它是一种痛苦。这是在没有 SimpleXML 的情况下如何做到的:

require 'json/add/core'
require 'nokogiri'

xml_files =<<EOT
<xml_root>
  <listing>
    <id>abc12345</id>
    <name>BCD</name>
    <address>12 Main St</address>
  </listing>
  <listing>
    <id>a1b2c3d4</id>
    <name>XYZ</name>
    <address>14 Main St</address>
  </listing>
  <listing>
    <id>bcde45678</id>
    <name>MNO</name>
    <address>14 Broadway</address>
  </listing>
</xml_root>
EOT

doc = Nokogiri::XML(xml_files)

xml_files = []
doc.search('listing').each do |listing|
  id, name, address = %w[id name address].map { |node| listing.at(node).content }
  File.write(
    id + '.json',
    {
      'id'      => id,
      'name'    => name,
      'address' => address
    }.to_json
  )
end
于 2013-06-20T21:03:55.477 回答