如何将Nokogiri Document对象转换为JSON [英] How to convert Nokogiri Document object into JSON

查看:75
本文介绍了如何将Nokogiri Document对象转换为JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些解析后的Nokogiri::XML::Document对象,我想将其打印为JSON.

I have some parsed Nokogiri::XML::Document objects that I want to print as JSON.

我可以采用以下方法:将其创建为字符串,将其解析为哈希,先使用active-record或Crack,再使用Hash.to_json;但这既丑陋,又取决于图书馆的管理方式.

I can go the route of making it a string, parsing it into a hash, with active-record or Crack and then Hash.to_json; but that is both ugly and depending on way too manay libraries.

有没有更简单的方法?

根据注释中的请求,例如XML <root a="b"><a>b</a></root>可以表示为JSON:

As per request in the comment, for example the XML <root a="b"><a>b</a></root> could be represented as JSON:

<root a="b"><a>b</a></root> #=> {"root":{"a":"b"}}
<root foo="bar"><a>b</a></root> #=> {"root":{"a":"b","foo":"bar"}}

这也是我现在使用Crack所获得的.而且,可以肯定的是,实体和子标签之间的冲突是一个潜在的问题,但是我自己构建了大多数XML,因此对我来说,最简单的是避免这些冲突:)

That is what I get with Crack now too. And, sure, collisions between entities and child-tags are a potential problem, but I build most of the XML myself, so it is easiest for me to avoid these collisions alltogether :)

推荐答案

这是一种方法.正如我的评论所指出的那样,正确"的答案取决于您的输出结果. JSON中没有XML节点的规范表示,因此所涉及的库没有内置这种功能:

Here's one way to do it. As noted by my comment, the 'right' answer depends on what your output should be. There is no canonical representation of XML nodes in JSON, and hence no such capability is built into the libraries involved:

require 'nokogiri'
require 'json'
class Nokogiri::XML::Node
  def to_json(*a)
    {"$name"=>name}.tap do |h|
      kids = children.to_a
      h.merge!(attributes)
      h.merge!("$text"=>text) unless text.empty?
      h.merge!("$kids"=>kids) unless kids.empty?
    end.to_json(*a)
  end
end
class Nokogiri::XML::Document
  def to_json(*a); root.to_json(*a); end
end
class Nokogiri::XML::Text
  def to_json(*a); text.to_json(*a); end
end
class Nokogiri::XML::Attr
  def to_json(*a); value.to_json(*a); end
end

xml = Nokogiri::XML '<root a="b" xmlns:z="zzz">
  <z:a>Hello <b z:x="y">World</b>!</z:a>
</root>'
puts xml.to_json

{
  "$name":"root",
  "a":"b",
  "$text":"Hello World!",
  "$kids":[
    {
      "$name":"a",
      "$text":"Hello World!",
      "$kids":[
        "Hello ",
        {
          "$name":"b",
          "x":"y",
          "$text":"World",
          "$kids":[
            "World"
          ]
        },
        "!"
      ]
    }
  ]
}

请注意,以上内容完全忽略了名称空间,它可能是您想要的,也可能不是您想要的.

Note that the above completely ignores namespaces, which may or may not be what you want.

这是转换为JsonML的另一种选择.虽然这是有损转换(它不支持注释节点,DTD或名称空间URL),并且格式在设计上有点愚蠢"(第一个子元素位于[1][2],具体取决于是还是不存在属性),它确实表示元素和属性的名称空间前缀:

Here's another alternative that converts to JsonML. While this is a lossy conversion (it does not support comment nodes, DTDs, or namespace URLs) and the format is a little bit "goofy" by design (the first child element is at [1] or [2] depending on whether or not attributes are present), it does indicate namespace prefixes for elements and attributes:

require 'nokogiri'
require 'json'
class Nokogiri::XML::Node
  def namespaced_name
    "#{namespace && "#{namespace.prefix}:"}#{name}"
  end
end
class Nokogiri::XML::Element
  def to_json(*a)
    [namespaced_name].tap do |parts|
      unless attributes.empty?
        parts << Hash[ attribute_nodes.map{ |a| [a.namespaced_name,a.value] } ]
      end
      parts.concat(children.select{|n| n.text? ? (n.text=~/\S/) : n.element? })
    end.to_json(*a)
  end
end
class Nokogiri::XML::Document
  def to_json(*a); root.to_json(*a); end
end
class Nokogiri::XML::Text
  def to_json(*a); text.to_json(*a); end
end
class Nokogiri::XML::Attr
  def to_json(*a); value.to_json(*a); end
end

xml = Nokogiri::XML '<root a="b" xmlns:z="zzz">
  <z:a>Hello <b z:x="y">World</b>!</z:a>
</root>'
puts xml.to_json
#=> ["root",{"a":"b"},["z:a","Hello ",["b",{"z:x":"y"},"World"],"!"]]

这篇关于如何将Nokogiri Document对象转换为JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆