Search code examples
rubycase-sensitivexml-simple

Case-sensitive XML parser for Ruby


I'm currently using XmlSimple in Ruby to convert XML to a hash using the xml_in method. Everything is really nice, except for the fact that the resulting hash keys are all lowercase, whereas the XML element names were mixed-case.

Here's an example:

hash = XmlSimple.xml_in( xml_string, { 'KeyAttr' => 'name',
                                       'ForceArray' => false,
                                       'NoAttr' => true,
                                       'KeyToSymbol' => true,
                                       'SuppressEmpty' => "" } )

So, for example, this xml:

<aclEntry>
  <aclEntryId>Stuff here</aclEntryId>
  <principalName>Stuff here</principalName>
</aclEntry>

results in this hash:

{ :aclentryid => "Stuff Here", :principalname => "Stuff here" } 

I've looked over the documentation for XmlSimple, and didn't see any option that indicated it could maintain mixed-case in the document-to-hash conversion.

Is there any way to use XmlSimple to maintain case sensitivity in the resulting hash? If not, is there an alternative Ruby XML parser that can generate a hash that maintains case-sensitivity like this?


Solution

  • Combination of Nokogiri and Activesupport will help.

    require 'active_support/core_ext/hash/conversions'
    require 'nokogiri'
    require 'pp'
    
    xml_doc  = Nokogiri::XML("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
    
    h = Hash.from_xml(xml_doc.to_s).symbolize_keys
    
    pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
    

    You can also do the same with ReXML and Activesupport

    require 'rexml/document'
    require 'pp'
    include REXML
    require 'active_support/core_ext/hash/conversions'
    
    xmldoc = Document.new("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
    
    h = Hash.from_xml(xmldoc.to_s).symbolize_keys
    
    pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
    

    EDIT : Having done a bit of reading it turns out that passing some options to SimpleXML produces the result you want, except that it doesn't symbolize the hash keys but that's a different issue.

    require 'xmlsimple'
    require 'pp'
    
    xml_str = <<XML_STR
    <aclEntry>
        <aclEntryId>Stuff here</aclEntryId>
        <principalName>Stuff here</principalName>
    </aclEntry>
    XML_STR
    
    result = XmlSimple.xml_in xml_str, { 'ForceArray' => false, 'AttrPrefix' => true, 'KeyToSymbol' => true }
    
    pp result # =>{:principalName=>"Stuff here", :aclEntryId=>"Stuff here"}