aboutsummaryrefslogblamecommitdiffstats
path: root/activesupport/lib/active_support/xml_mini/nokogiri.rb
blob: 1987330c25c5d7497083ab074ea171975d91a8e1 (plain) (tree)
1
2
3
4
5
6
7
8
9
                             
 
     
                    



                                                                                                                            
                                           
                  
 



                                  



                                                                                    
                                 
                                       
         
 
                  

          
                                 
                                                       
                   
         

       

                               




                      
                          
                                           
 
                                       


                                                     
                              
                        
 

                                                        


                                                              
             
 




                                     
                                                
                                                  
               
             
 



                                                                       
 

                                                                       
 
              



           

                                                          

     
# frozen_string_literal: true

begin
  require "nokogiri"
rescue LoadError => e
  $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install"
  raise e
end
require_relative "../core_ext/object/blank"
require "stringio"

module ActiveSupport
  module XmlMini_Nokogiri #:nodoc:
    extend self

    # Parse an XML Document string or IO into a simple hash using libxml / nokogiri.
    # data::
    #   XML Document string or IO to parse
    def parse(data)
      if !data.respond_to?(:read)
        data = StringIO.new(data || "")
      end

      if data.eof?
        {}
      else
        doc = Nokogiri::XML(data)
        raise doc.errors.first if doc.errors.length > 0
        doc.to_hash
      end
    end

    module Conversions #:nodoc:
      module Document #:nodoc:
        def to_hash
          root.to_hash
        end
      end

      module Node #:nodoc:
        CONTENT_ROOT = "__content__".freeze

        # Convert XML document to hash.
        #
        # hash::
        #   Hash to merge the converted element into.
        def to_hash(hash = {})
          node_hash = {}

          # Insert node hash into parent hash correctly.
          case hash[name]
          when Array then hash[name] << node_hash
          when Hash  then hash[name] = [hash[name], node_hash]
          when nil   then hash[name] = node_hash
          end

          # Handle child elements
          children.each do |c|
            if c.element?
              c.to_hash(node_hash)
            elsif c.text? || c.cdata?
              node_hash[CONTENT_ROOT] ||= "".dup
              node_hash[CONTENT_ROOT] << c.content
            end
          end

          # Remove content node if it is blank and there are child tags
          if node_hash.length > 1 && node_hash[CONTENT_ROOT].blank?
            node_hash.delete(CONTENT_ROOT)
          end

          # Handle attributes
          attribute_nodes.each { |a| node_hash[a.node_name] = a.value }

          hash
        end
      end
    end

    Nokogiri::XML::Document.include(Conversions::Document)
    Nokogiri::XML::Node.include(Conversions::Node)
  end
end