4

私は次のようにxmlを返しているAPIからデータを取得しています:

<?xml version="1.0" encoding="utf-8" ?> <seriess realtime_start="2013-01-28" realtime_end="2013-01-28"> <series id="GDPC1" realtime_start="2013-01-28" realtime_end="2013-01-28" title="Real Gross Domestic Product, 1 Decimal" observation_start="1947-01-01" observation_end="2012-07-01" frequency="Quarterly" frequency_short="Q" units="Billions of Chained 2005 Dollars" units_short="Bil. of Chn. 2005 $" seasonal_adjustment="Seasonally Adjusted Annual Rate" seasonal_adjustment_short="SAAR" last_updated="2012-12-20 08:16:28-06" popularity="93" notes="Real gross domestic product is the inflation adjusted value of the goods and services produced by labor and property located in the United States. For more information see the Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)"/> </seriess>

デシリアライズは初めてですが、このxmlを解析してrubyオブジェクトにし、objectFoo.seriess.series.frequencyのように参照して「Quarterly」を返すことが適切だと思います。

こことグーグルでの私の検索から、Ruby(レールではない)でこれに対する明白な解決策がないようであり、それは私がかなり明白な何かを見逃していると私に思わせます。何か案は?

編集 私はWinfieldの提案に基づいてテストケースを設定しました。

class Exopenstruct

  require 'ostruct'

  def initialize()  

  hash = {"seriess"=>{"realtime_start"=>"2013-02-01", "realtime_end"=>"2013-02-01", "series"=>{"id"=>"GDPC1", "realtime_start"=>"2013-02-01", "realtime_end"=>"2013-02-01", "title"=>"Real Gross Domestic Product, 1 Decimal", "observation_start"=>"1947-01-01", "observation_end"=>"2012-10-01", "frequency"=>"Quarterly", "frequency_short"=>"Q", "units"=>"Billions of Chained 2005 Dollars", "units_short"=>"Bil. of Chn. 2005 $", "seasonal_adjustment"=>"Seasonally Adjusted Annual Rate", "seasonal_adjustment_short"=>"SAAR", "last_updated"=>"2013-01-30 07:46:54-06", "popularity"=>"93", "notes"=>"Real gross domestic product is the inflation adjusted value of the goods and services produced by labor and property located in the United States.\n\nFor more information see the Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)"}}}

  object_instance = OpenStruct.new( hash )

  end
end

irbで、rbファイルをロードし、クラスをインスタンス化しました。ただし、属性(instance.seriesなど)にアクセスしようとすると、次のメッセージが表示されます。NoMethodError:undefined method `seriess '

明らかな何かが欠けている場合は、もう一度お詫び申し上げます。

4

4 に答える 4

16

Railsに含まれているような、標準のXMLからハッシュへの解析を使用する方がよい場合があります。

object_hash = Hash.from_xml(xml_string)
puts object_hash['seriess']

Railsスタックを使用していない場合は、同じ動作のためにNokogiriのようなライブラリを使用できます。

編集:オブジェクトの動作を探している場合、OpenStructを使用することは、このためのハッシュをラップするための優れた方法です。

object_instance = OpenStruct.new( Hash.from_xml(xml_string) )
puts object_instance.seriess

注:深くネストされたデータの場合、埋め込まれたハッシュをOpenStructインスタンスに再帰的に変換する必要がある場合もあります。IE:上記の属性が値のハッシュである場合、OpenStructではなくハッシュになります。

于 2013-01-30T18:46:42.603 に答える
4

Damien Le BerrigaudのHappyMapperのフォークを使い始めたばかりで、本当に満足しています。単純なRubyクラスとを定義しますinclude HappyMapper。を呼び出すとparse、Nokogiriを使用してXMLを丸呑みし、真正なRubyオブジェクトの完全なツリーを取得します。

私はこれを使用して数メガバイトのXMLファイルを解析しましたが、高速で信頼性が高いことがわかりました。READMEを確認してください。

ヒント:XMLファイルのエンコード文字列が嘘をつくことがあるため、次のようにXMLをサニタイズする必要がある場合があります。

def sanitize(xml)
  xml.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
end

NokogiriのInput is not proper UTF-8, indicate encoding !エラーを回避するために、#parseメソッドに渡す前に。

アップデート

私は先に進み、OPの例をHappyMapperにキャストしました。

XML_STRING = '<?xml version="1.0" encoding="utf-8" ?> <seriess realtime_start="2013-01-28" realtime_end="2013-01-28"> <series id="GDPC1" realtime_start="2013-01-28" realtime_end="2013-01-28" title="Real Gross Domestic Product, 1 Decimal" observation_start="1947-01-01" observation_end="2012-07-01" frequency="Quarterly" frequency_short="Q" units="Billions of Chained 2005 Dollars" units_short="Bil. of Chn. 2005 $" seasonal_adjustment="Seasonally Adjusted Annual Rate" seasonal_adjustment_short="SAAR" last_updated="2012-12-20 08:16:28-06" popularity="93" notes="Real gross domestic product is the inflation adjusted value of the goods and services produced by labor and property located in the United States. For more information see the Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)"/> </seriess>'

class Series; end;              # fwd reference

class Seriess
  include HappyMapper
  tag 'seriess'

  attribute :realtime_start, Date
  attribute :realtime_end, Date
  has_many :seriess, Series, :tag => 'series'
end
class Series
  include HappyMapper
  tag 'series'

  attribute 'id', String
  attribute 'realtime_start', Date
  attribute 'realtime_end', Date
  attribute 'title', String
  attribute 'observation_start', Date
  attribute 'observation_end', Date
  attribute 'frequency', String
  attribute 'frequency_short', String
  attribute 'units', String
  attribute 'units_short', String
  attribute 'seasonal_adjustment', String
  attribute 'seasonal_adjustment_short', String
  attribute 'last_updated', DateTime
  attribute 'popularity', Integer
  attribute 'notes', String
end

def test
  Seriess.parse(XML_STRING, :single => true)
end

そして、これがあなたがそれでできることです:

>> a = test
>> a.class
Seriess
>> a.seriess.first.frequency
=> "Quarterly"
>> a.seriess.first.observation_start
=> #<Date: 1947-01-01 ((2432187j,0s,0n),+0s,2299161j)>
>> a.seriess.first.popularity
=> 93
于 2013-10-30T14:14:07.053 に答える
1

Nokogiriは構文解析を解決します。データの処理方法はあなた次第です。ここでOpenStructは例として使用します。

require 'nokogiri'
require 'ostruct'
require 'open-uri'

doc = Nokogiri.parse open('http://www.w3schools.com/xml/note.xml')

note = OpenStruct.new

note.to = doc.at('to').text
note.from = doc.at('from').text
note.heading = doc.at('heading').text
note.body = doc.at('body').text

=> #<OpenStruct to="Tove", from="Jani", heading="Reminder", body="ToveJaniReminderDon't forget me this weekend!\r\n">

これは単なるティーザーであり、問​​題の大きさは何倍も大きくなる可能性があります。作業を開始するためのエッジを与えるだけです


編集:グーグルとstackoverflowに出くわしました私はレールを使用して私の答えと@WinfieldHash#from_xmlの間に可能なハイブリッドに遭遇しました:

> require 'active_support/core_ext/hash/conversions'
> xml = Nokogiri::XML.parse(open('http://www.w3schools.com/xml/note.xml'))
> Hash.from_xml(xml.to_s)
=> {"note"=>{"to"=>"Tove", "from"=>"Jani", "heading"=>"Reminder", "body"=>"Don't forget me this weekend!"}}

次に、このハッシュを使用して、たとえば、新しいActiveRecord::Baseモデルインスタンスまたはそれを使用して行うことを決定したその他のインスタンスを初期化できます。

http://nokogiri.org/
http://ruby-doc.org/stdlib-1.9.3/libdoc/ostruct/rdoc/OpenStruct.html https://stackoverflow.com/a/7488299/1740079

于 2013-01-30T19:06:03.553 に答える
0

xmlをハッシュに変換したい場合は、norigem最も単純であることがわかりました。

例:

require 'nori'

xml = '<?xml version="1.0" encoding="utf-8" ?> <seriess realtime_start="2013-01-28" realtime_end="2013-01-28"> <series id="GDPC1" realtime_start="2013-01-28" realtime_end="2013-01-28" title="Real Gross Domestic Product, 1 Decimal" observation_start="1947-01-01" observation_end="2012-07-01" frequency="Quarterly" frequency_short="Q" units="Billions of Chained 2005 Dollars" units_short="Bil. of Chn. 2005 $" seasonal_adjustment="Seasonally Adjusted Annual Rate" seasonal_adjustment_short="SAAR" last_updated="2012-12-20 08:16:28-06" popularity="93" notes="Real gross domestic product is the inflation adjusted value of the goods and services produced by labor and property located in the United States. For more information see the Guide to the National Income and Product Accounts of the United States (NIPA) - (http://www.bea.gov/national/pdf/nipaguid.pdf)"/> </seriess>'

hash = Nori.new.parse(xml)    
hash['seriess']
hash['seriess']['series']
puts hash['seriess']['series']['@frequency']

「@」は要素ではなく「シリーズ」の属性であるため、頻度に使用されることに注意してください。

于 2018-02-28T19:14:02.260 に答える