How to convert a nested hash into XML using Nokogiri

前端 未结 3 725
感动是毒
感动是毒 2021-01-05 01:01

I have many levels of a nested hash like:

 { :foo => \'bar\', :foo1 => { :foo2 => \'bar2\', :foo3 => \'bar3\', :foo4 => { :foo5 => \'bar5\'         


        
3条回答
  •  天涯浪人
    2021-01-05 01:31

    The accepted is a clean solution, but the below really does 'use' Nokogiri to construct XML from a Hash with special handling for attributes:

    require 'nokogiri'
    
    def generate_xml(data, parent = false, opt = {})
        return if data.to_s.empty?
        return unless data.is_a?(Hash)
    
        unless parent
            # assume that if the hash has a single key that it should be the root
            root, data = (data.length == 1) ? data.shift : ["root", data]
            builder = Nokogiri::XML::Builder.new(opt) do |xml|
                xml.send(root) {
                    generate_xml(data, xml)
                }
            end
    
            return builder.to_xml
        end
    
        data.each { |label, value|
            if value.is_a?(Hash)
                attrs = value.fetch('@attributes', {})
                # also passing 'text' as a key makes nokogiri do the same thing
                text = value.fetch('@text', '') 
                parent.send(label, attrs, text) { 
                    value.delete('@attributes')
                    value.delete('@text')
                    generate_xml(value, parent)
                }
    
            elsif value.is_a?(Array)
                value.each { |el|
                    # lets trick the above into firing so we do not need to rewrite the checks
                    el = {label => el}
                    generate_xml(el, parent) 
                }
    
            else
                parent.send(label, value)
            end
        }
    end
    
    puts generate_xml(
        {'myroot' => 
            {
                'num' => 99, 
                'title' => 'something witty', 
                'nested' => { 'total' => [99, 98], '@attributes' => {'foo' => 'bar', 'hello' => 'world'}}, 
                'anothernest' => {
                    '@attributes' => {'foo' => 'bar', 'hello' => 'world'}, 
                    'date' => [
                        'today', 
                        {'day' => 23, 'month' => 'Dec', 'year' => {'y' => 1999, 'c' => 21}, '@attributes' => {'foo' => 'blhjkldsaf'}}
                    ]
                }
        }})
    puts puts
    puts generate_xml({
                'num' => 99, 
                'title' => 'something witty', 
                'nested' => { 'total' => [99, 98], '@attributes' => {'foo' => 'bar', 'hello' => 'world'}}, 
                'anothernest' => {
                    '@attributes' => {'foo' => 'bar', 'hello' => 'world'}, 
                    'date' => [
                        'today', 
                        {'day' => [23,24], 'month' => 'Dec', 'year' => {'y' => 1999, 'c' => 21}, '@attributes' => {'foo' => 'blhjkldsaf'}}
                    ]
                }
        })
    

    And the resulting XML output:

    
    
      99
      something witty
      
        99
        98
      
      
        today
        
          23
          Dec
          
            1999
            21
          
        
      
    
    
    
    
    
      99
      something witty
      
        99
        98
      
      
        today
        
          23
          24
          Dec
          
            1999
            21
          
        
      
    
    

提交回复
热议问题