Program Tip

Nokogiri 문서를 Ruby Hash로 변환

programtip 2020. 11. 13. 23:58
반응형

Nokogiri 문서를 Ruby Hash로 변환


Nokogiri XML 문서를 해시로 변환하는 쉬운 방법이 있습니까?

Rails의 Hash.from_xml.


이 코드를 libxml-ruby (1.1.3)와 함께 사용합니다. 나는 nokogiri를 직접 사용하지 않았지만 어쨌든 libxml-ruby를 사용한다는 것을 이해합니다. xml 요소를 루비 객체에 매핑하는 ROXML ( http://github.com/Empact/roxml/tree )도 살펴 보시기 바랍니다 . libxml 위에 빌드됩니다.

# USAGE: Hash.from_libxml(YOUR_XML_STRING)
require 'xml/libxml'
# adapted from 
# http://movesonrails.com/articles/2008/02/25/libxml-for-active-resource-2-0

class Hash 
  class << self
        def from_libxml(xml, strict=true) 
          begin
            XML.default_load_external_dtd = false
            XML.default_pedantic_parser = strict
            result = XML::Parser.string(xml).parse 
            return { result.root.name.to_s => xml_node_to_hash(result.root)} 
          rescue Exception => e
            # raise your custom exception here
          end
        end 

        def xml_node_to_hash(node) 
          # If we are at the root of the document, start the hash 
          if node.element? 
           if node.children? 
              result_hash = {} 

              node.each_child do |child| 
                result = xml_node_to_hash(child) 

                if child.name == "text"
                  if !child.next? and !child.prev?
                    return result
                  end
                elsif result_hash[child.name.to_sym]
                    if result_hash[child.name.to_sym].is_a?(Object::Array)
                      result_hash[child.name.to_sym] << result
                    else
                      result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << result
                    end
                  else 
                    result_hash[child.name.to_sym] = result
                  end
                end

              return result_hash 
            else 
              return nil 
           end 
           else 
            return node.content.to_s 
          end 
        end          
    end
end

Nokogiri XML 문서를 해시로 변환하려면 다음을 수행하십시오.

require 'active_support/core_ext/hash/conversions'
hash = Hash.from_xml(nokogiri_document.to_s)

다음은 요소와 속성 모두에 대한 네임 스페이스 정보를 포함하는 강력한 해시를 만드는 훨씬 더 간단한 버전입니다.

require 'nokogiri'
class Nokogiri::XML::Node
  TYPENAMES = {1=>'element',2=>'attribute',3=>'text',4=>'cdata',8=>'comment'}
  def to_hash
    {kind:TYPENAMES[node_type],name:name}.tap do |h|
      h.merge! nshref:namespace.href, nsprefix:namespace.prefix if namespace
      h.merge! text:text
      h.merge! attr:attribute_nodes.map(&:to_hash) if element?
      h.merge! kids:children.map(&:to_hash) if element?
    end
  end
end
class Nokogiri::XML::Document
  def to_hash; root.to_hash; end
end

실제 모습 :

xml = '<r a="b" xmlns:z="foo"><z:a>Hello <b z:m="n" x="y">World</b>!</z:a></r>'
doc = Nokogiri::XML(xml)
p doc.to_hash
#=> {
#=>   :kind=>"element",
#=>   :name=>"r",
#=>   :text=>"Hello World!",
#=>   :attr=>[
#=>     {
#=>       :kind=>"attribute",
#=>       :name=>"a", 
#=>       :text=>"b"
#=>     }
#=>   ], 
#=>   :kids=>[
#=>     {
#=>       :kind=>"element", 
#=>       :name=>"a", 
#=>       :nshref=>"foo", 
#=>       :nsprefix=>"z", 
#=>       :text=>"Hello World!", 
#=>       :attr=>[], 
#=>       :kids=>[
#=>         {
#=>           :kind=>"text", 
#=>           :name=>"text", 
#=>           :text=>"Hello "
#=>         },
#=>         {
#=>           :kind=>"element", 
#=>           :name=>"b", 
#=>           :text=>"World", 
#=>           :attr=>[
#=>             {
#=>               :kind=>"attribute", 
#=>               :name=>"m", 
#=>               :nshref=>"foo", 
#=>               :nsprefix=>"z", 
#=>               :text=>"n"
#=>             },
#=>             {
#=>               :kind=>"attribute", 
#=>               :name=>"x", 
#=>               :text=>"y"
#=>             }
#=>           ], 
#=>           :kids=>[
#=>             {
#=>               :kind=>"text", 
#=>               :name=>"text", 
#=>               :text=>"World"
#=>             }
#=>           ]
#=>         },
#=>         {
#=>           :kind=>"text", 
#=>           :name=>"text", 
#=>           :text=>"!"
#=>         }
#=>       ]
#=>     }
#=>   ]
#=> }

나는 단순히 XML을 (Rails가 아닌) Hash로 변환하려고 시도하면서 이것을 발견했습니다. 나는 Nokogiri를 사용할 것이라고 생각했지만 결국 Nori를 사용하게되었습니다 .

Then my code was trival:

response_hash = Nori.parse(response)

Other users have pointed out that this does not work. I have not verified, but it seems that the parse method has been moved from the class to the instance. My code above worked at some point. New (unverified) code would be:

response_hash = Nori.new.parse(response)

Use Nokogiri to parse XML response to ruby hash. It's pretty fast.

doc = Nokogiri::XML(response_body) 
Hash.from_xml(doc.to_s)

If you define something like this in your configuration:

ActiveSupport::XmlMini.backend = 'Nokogiri'

it includes a module in Nokogiri and you gain the to_hash method.


If the node you've selected in Nokogiri consists of only one tag, you can extract the keys, values and zip them into one hash, like so:

  @doc ||= Nokogiri::XML(File.read("myxmldoc.xml"))
  @node = @doc.at('#uniqueID') # this works if this selects only one node
  nodeHash = Hash[*@node.keys().zip(@node.values()).flatten]

See http://www.ruby-forum.com/topic/125944 for more info on Ruby array merging.


Have a look at the simple mix-in I made for the Nokogiri XML Node.

http://github.com/kuroir/Nokogiri-to-Hash

Here's a usage example:

require 'rubygems'
require 'nokogiri'
require 'nokogiri_to_hash'
html = '
  <div id="hello" class="container">
    <p>Hello! visit my site <a href="http://kuroir.com">Kuroir.com</a></p>
  </div>
'
p Nokogiri.HTML(html).to_hash
=> [{:div=>{:class=>["container"], :children=>[{:p=>{:children=>[{:a=>{:href=>["http://kuroir.com"], :children=>[]}}]}}], :id=>["hello"]}}]

참고URL : https://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash

반응형