1

Noriを使用してXMLドキュメントをRubyハッシュに変換しようとしています。ただし、ルート要素のコレクションを受け取る代わりに、コレクションを含む新しいノードが返されます。これは私がしていることです:

@xml  = content_for(:layout)
@hash = Nori.new(:parser => :nokogiri, :advanced_typecasting => false).parse(@xml)

また

@hash = Hash.from_xml(@xml)

の内容@xmlは次のとおりです。

<bundles>
  <bundle>
    <id>6073</id>
    <name>Bundle-1</name>
    <status>1</status>
    <bundle_type>
      <id>6713</id>
      <name>BundleType-1</name>
    </bundle_type>
    <begin_at nil=\"true\"></begin_at>
    <end_at nil=\"true\"></end_at>
    <updated_at>2013-03-21T23:02:32Z</updated_at>
    <created_at>2013-03-21T23:02:32Z</created_at>
  </bundle>
  <bundle>
    <id>6074</id>
    <name>Bundle-2</name>
    <status>1</status>
    <bundle_type>
      <id>6714</id>
      <name>BundleType-2</name>
    </bundle_type>
    <begin_at nil=\"true\"></begin_at>
    <end_at nil=\"true\"></end_at>
    <updated_at>2013-03-21T23:02:32Z</updated_at>
    <created_at>2013-03-21T23:02:32Z</created_at>
  </bundle>
</bundles>

パーサーは@hash次の形式を返します。

{"bundles"=>{"bundle"=>[{"id"=>"6073", "name"=>"Bundle-1", "status"=>"1", "bundle_type"=>{"id"=>"6713", "name"=>"BundleType-1"}, "begin_at"=>nil, "end_at"=>nil, "updated_at"=>"2013-03-21T23:02:32Z", "created_at"=>"2013-03-21T23:02:32Z"}, {"id"=>"6074", "name"=>"Bundle-2", "status"=>"1", "bundle_type"=>{"id"=>"6714", "name"=>"BundleType-2"}, "begin_at"=>nil, "end_at"=>nil, "updated_at"=>"2013-03-21T23:02:32Z", "created_at"=>"2013-03-21T23:02:32Z"}]}} 

代わりに私は取得したいと思います:

{"bundles"=>[{"id"=>"6073", "name"=>"Bundle-1", "status"=>"1", "bundle_type"=>{"id"=>"6713", "name"=>"BundleType-1"}, "begin_at"=>nil, "end_at"=>nil, "updated_at"=>"2013-03-21T23:02:32Z", "created_at"=>"2013-03-21T23:02:32Z"}, {"id"=>"6074", "name"=>"Bundle-2", "status"=>"1", "bundle_type"=>{"id"=>"6714", "name"=>"BundleType-2"}, "begin_at"=>nil, "end_at"=>nil, "updated_at"=>"2013-03-21T23:02:32Z", "created_at"=>"2013-03-21T23:02:32Z"}]}

重要なのは、XMLを制御することです。XMLは、上記の方法と同様に形成された場合に使用されます。

私の質問は、RABLのJSON出力が標準に準拠していないかどうかにも関連していますか?それをできる?

4

2 に答える 2

1

同じタグのリストのみで構成されるXMLを想像してみてください。

<shoppinglist>
    <item>apple</item>
    <item>banana</item>
    <item>cherry</item>
    <item>pear</item>
<shoppinglist>

これをハッシュに変換する場合、たとえばを使用してアイテムにアクセスするのは非常に簡単hash['shoppinglist']['item'][0]です。しかし、この場合、あなたは何を期待しますか?ただの配列?あなたの論理によれば、アイテムはこれでアクセス可能になるはずhash['shoppinglist'][0]ですが、コンテナ内に異なる要素がある場合はどうなりますか?

<shoppinglist>
    <date>2013-01-01</date>
    <item>apple</item>
    <item>banana</item>
    <item>cherry</item>
    <item>pear</item>
<shoppinglist>

どのようにアイテムにアクセスしますか?そして、どのように日付?問題は、ハッシュへの変換が一般的な場合に機能しなければならないことです。

私は海苔を知りませんが、一般的なケースを考えると意味がないという理由だけで、あなたがそれから尋ねるものが焼き付けられていないことはかなり確信しています。別の方法として、バンドル配列を自分で1レベル上げることもできます。

@hash['bundles'] = @hash['bundles']['bundle']
于 2013-03-22T01:24:04.000 に答える
1

あなたの問題に対する一般的な解決策はあまりきれいではありません。

ArrayHash という名前の特別なオブジェクトを作成しました。これには、キーが 1 つしかなく、そのキーが指すデータの値が配列である場合、それらの配列要素に整数キーを追加するという特別なプロパティがあります。

したがって、通常の RubyHash辞書が次のように見える場合

{bundle"=>["0", "1", "A", "B"]}

次に、ArrayHash辞書では次のようになります

{"bundle"=>["0", "1", "A", "B"], 0=>"0", 1=>"1", 2=>"A", 3=>"B"}

追加のキーは 型であるため、FixnumこのハッシュはArray

[ "0", "1", "A", "B" ]

ただし、「バンドル」エントリもあるため、サイズは 5 です。

Nori以下は、この特別な Dictionary の使用を強制するコードです。

require 'nori'

class Nori
  class ArrayHash < Hash
    def [](a)
      if a.is_a? Fixnum and self.size == 1
        key = self.keys[0]
        self[key][a]
      else
        super
      end
    end
    def inspect
      if self.size == 1 and self.to_a[0][1].class == Array
        p = Hash[self.to_a]
        self.values[0].each.with_index do |v, i|
          p[i] = v
        end
        p.inspect
      else
        super
      end
    end
  end
end

class Nori
  class XMLUtilityNode
    alias :old_to_hash :to_hash
    def to_hash
      ret = old_to_hash
      raise if ret.size != 1
      raise unless ret.class == Hash
      a = ret.to_a[0]
      k, v = a.first, a.last
      if v.class == Hash
        v = ArrayHash[ v.to_a ]
      end
      ret = ArrayHash[ k, v ]
      ret
    end
  end
end


h = Nori.new(:parser => :nokogiri, :advanced_typecasting => false).parse(<<EOF)
<top>
<aundles>
  <bundle>0</bundle>
  <bundle>1</bundle>
  <bundle>A</bundle>
  <bundle>B</bundle>
</aundles>
<bundles>
  <nundle>A</nundle>
  <bundle>A</bundle>
  <bundle>B</bundle>
</bundles>
</top>
EOF

puts "#{h['top']['aundles'][0]} == #{ h['top']['aundles']['bundle'][0]}"
puts "#{h['top']['aundles'][1]} == #{ h['top']['aundles']['bundle'][1]}"
puts "#{h['top']['aundles'][2]} == #{ h['top']['aundles']['bundle'][2]}"
puts "#{h['top']['aundles'][3]} == #{ h['top']['aundles']['bundle'][3]}"

puts h.inspect

出力は次のとおりです。

0 == 0
1 == 1
A == A
B == B
{"top"=>{"aundles"=>{"bundle"=>["0", "1", "A", "B"], 0=>"0", 1=>"1", 2=>"A", 3=>"B"}, "bundles"=>{"nundle"=>"A", "bundle"=>["A", "B"]}}}
于 2016-09-03T18:18:17.023 に答える