2013-03-26 2 views
1

XML 구조를 레일에서 Hash.from_xml(@xml)으로 해시로 변환하면 파서는 빈 배열과 nil 값을 구별하지 않지만 XML은 \으로 즉시 종료되어 빈 배열이됩니다. <audio_languages/>과 속성이 nil="true" 인 경우는 nil 값으로 해석됩니다.빈 배열과 nil 값이 보존되는 레일에서 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)에서 예상되는 출력은 다음과 같습니다 : (I 생성하는 방법에 대한 통제권이)

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을 사용하여 노드 구문 분석을 끝내고 빈 배열 대 nil 값으로 변환 할 것인지를 결정하기 위해 노드에 서명이 있는지 확인합니다.

# 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