2013-03-26 28 views
1

当我转换XML结构与导轨Hash.from_xml(@xml)散列,解析器不空数组和零值之间的区分的Rails,而XML描述节点那立即以\终止为空数组,例如<audio_languages/>与那些属性为nil="true"的人被解释为零值。如何转换XML散列在空数组和零值被保留

的XML结构(这是我可以控制如何生成)看起来是这样的:

<response> 
    <medias> 
    <media> 
     <id>1</id> 
     <name>Media-1</name> 
     <audio_languages/> 
     <avg_rating nil="true"></avg_rating> 
    </media> 
    <media> 
     <id>2</id> 
     <name>Media-2</name> 
     <audio_languages/> 
     <avg_rating nil="true"></avg_rating> 
    </media> 
    </medias> 
</response> 

Hash.from_xml(@xml)预期结果将是:

{"response"=>{"medias"=>{"media"=>[{"id"=>"1", "name"=>"Media-1", "audio_languages"=>[], "avg_rating"=>nil}, {"id"=>"2", "name"=>"Media-2", "audio_languages"=>[], "avg_rating"=>nil}]}}} 

相反,我得到零值对于audio_languagesavg_rating

{"response"=>{"medias"=>{"media"=>[{"id"=>"1", "name"=>"Media-1", "audio_languages"=>nil, "avg_rating"=>nil}, {"id"=>"2", "name"=>"Media-2", "audio_languages"=>nil, "avg_rating"=>nil}]}}} 

回答

0

我结束了使用libxml解析节点,我正在检查节点是否具有我正在查找的签名,以便确定是否要将其作为空数组转换为零值。

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

class Hash 
    class << self 
    def from_xml_with_libxml(xml, strict=true) 
     LibXML::XML.default_load_external_dtd = false 
     LibXML::XML.default_pedantic_parser = strict 
     result = LibXML::XML::Parser.string(xml).parse 
     return { result.root.name.to_s => xml_node_to_hash_with_libxml(result.root)} 
    end 

    def xml_node_to_hash_with_libxml(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_with_libxml(child) 

      if child.name == "text" 
       if !child.next? and !child.prev? 
       return result 
       end 
      elsif result_hash[child.name] 
       if result_hash[child.name].is_a?(Object::Array) 
       result_hash[child.name] << result 
       else 
       result_hash[child.name] = [result_hash[child.name]] << result 
       end 
      else 
       result_hash[child.name] = result 
      end 
      end 
      return result_hash 
     else 
      # Nodes of sort <audio_languages/>, are arrays, 
      # and nodes like <average_rating "nil"="true"/> are nil values. 
      if node.to_s.match(/^\<(.+)\/\>$/) && nil == node.attributes["nil"] 
      return [] 
      end 
      return nil 
     end 
     else 
     return node.content.to_s 
     end 
    end   
    end 
end