如何迭代使用Rails的Hash#to_xml创建的哈希?

时间:2013-01-10 19:06:30

标签: ruby-on-rails ruby xml hash iteration

我正在使用thetvdb.com API获取节目的剧集列表。通常,XML格式类似于:

<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
<Episode><EpisodeName>Bar</EpisodeName><EpisodeNumber>2</EpisodeNumber></Episode>
</Data>

我所做的是使用Hash.from_xml解析XML,然后处理数据。为了迭代剧集,我做了类似的事情:

hash_data['Data']['Episode'].each do ...

如果有多集,这会很有效。但是如果只有一集,each方法实际上会遍历该单个特定剧集的哈希条目,而不是仅运行each方法一次。这打破了我的所有代码。

我试过了:

hash_data['Data']['Episode'].to_a.each do ...

具有相同的结果。必须采用“正确”的方式来做到这一点吗?

更新:我认为这个问题相当清楚,但似乎让人感到困惑。为了澄清,我真的试图迭代剧集并查看内容。数据最初是作为XML接收的,因此为了在Ruby中检查它,我使用Hash.from_xml(xml_response)将其转换为哈希。

就“预期行为”而言,请举例:

hash_data['Data']['Episode'].each do |e| { puts e['EpisodeNumber'] }

我希望给出这个初始数据:

<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
<Episode><EpisodeName>Bar</EpisodeName><EpisodeNumber>2</EpisodeNumber></Episode>
</Data>

输出结果为:

1
2

有效。但是,如果我得到这样的输入:

<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
</Data>

我遇到了崩溃,因为e['EpisodeNumber']无效。这是无效的,因为在只有一集的情况下,each实际上遍历哈希的每个键(因此进入each块的第一个值是一个键-value对EpisodeName)而不是一个哈希数组,就像有多个元素时一样。

换句话说,当有多集时,hash_data['Data']['Episode']ArrayHash类型。当只有一集时,它只是一个Hash。如果在有一集的情况下,仍然 Array,但其中只有一个项目,我的代码将正常工作。但事实并非如此。我该如何妥善处理?

我希望能搞清楚吗?

更新2 :已请求我为返回的数据发布Hash#inspect。这是一集剧集的节目:

{"Data"=>{"Series"=>{"id"=>"263752", "Actors"=>"||", "Airs_DayOfWeek"=>"Thursday", "Airs_Time"=>"10pm", "ContentRating"=>nil, "FirstAired"=>"2013-01-17", "Genre"=>"|Game Show|Reality|", "IMDB_ID"=>"tt2401129", "Language"=>"en", "Network"=>"TBS Superstation", "NetworkID"=>nil, "Overview"=>"Hosted by Robert Carradine and Curtis Armstrong, King of the Nerds is the ultimate nerd-off. The series will follow eleven fierce competitors from across the nerd spectrum as they set out to win $100,000 and be crowned the greatest nerd of them all.\n\nKing of the Nerds will take the glory of geekdom to a whole new level as the eleven competitors live together in \"Nerdvana.\" Each week, they must face challenges that will test their intellect, ingenuity, skills and pop culture prowess. In each episode, the nerds will first compete as teams and then as individuals, facing challenges that range from live gaming to a dance-off to life-sized chess. One competitor will be eliminated each week until one nerd stands alone as the ultimate champion off all things nerdy.", "Rating"=>nil, "RatingCount"=>"0", "Runtime"=>"60", "SeriesID"=>nil, "SeriesName"=>"King of the Nerds", "Status"=>"Continuing", "added"=>"2012-10-31 21:53:29", "addedBy"=>"348252", "banner"=>"graphical/263752-g2.jpg", "fanart"=>"fanart/original/263752-1.jpg", "lastupdated"=>"1357501598", "poster"=>nil, "zap2it_id"=>nil}, "Episode"=>{"id"=>"4428487", "Combined_episodenumber"=>"1", "Combined_season"=>"1", "DVD_chapter"=>nil, "DVD_discid"=>nil, "DVD_episodenumber"=>nil, "DVD_season"=>nil, "Director"=>nil, "EpImgFlag"=>nil, "EpisodeName"=>"Welcome to the Nerdvana", "EpisodeNumber"=>"1", "FirstAired"=>"2013-01-17", "GuestStars"=>nil, "IMDB_ID"=>nil, "Language"=>"en", "Overview"=>nil, "ProductionCode"=>nil, "Rating"=>nil, "RatingCount"=>"0", "SeasonNumber"=>"1", "Writer"=>nil, "absolute_number"=>nil, "filename"=>nil, "lastupdated"=>"1357501766", "seasonid"=>"504427", "seriesid"=>"263752"}}}

请注意,EpisodeHash类型。

这是一个有多个剧集的节目:

{"Data"=>{"Series"=>{"id"=>"220441", "Actors"=>"||", "Airs_DayOfWeek"=>"Saturday", "Airs_Time"=>"8:30PM", "ContentRating"=>"TV-PG", "FirstAired"=>"2010-12-25", "Genre"=>"|Children|Drama|", "IMDB_ID"=>"tt1765510", "Language"=>"en", "Network"=>"The Hub", "NetworkID"=>nil, "Overview"=>nil, "Rating"=>"7.0", "RatingCount"=>"1", "Runtime"=>"30", "SeriesID"=>nil, "SeriesName"=>"R L Stine's The Haunting Hour", "Status"=>"Continuing", "added"=>"2011-01-10 15:59:43", "addedBy"=>"66501", "banner"=>"graphical/220441-g.jpg", "fanart"=>"fanart/original/220441-1.jpg", "lastupdated"=>"1354439519", "poster"=>"posters/220441-1.jpg", "zap2it_id"=>nil}, "Episode"=>[{"id"=>"3453441", "Combined_episodenumber"=>"1", "Combined_season"=>"1", "DVD_chapter"=>nil, "DVD_discid"=>nil, "DVD_episodenumber"=>nil, "DVD_season"=>nil, "Director"=>nil, "EpImgFlag"=>"2", "EpisodeName"=>"Really You (Part 1)", "EpisodeNumber"=>"1", "FirstAired"=>"2010-10-29", "GuestStars"=>"|Bailee Madison|Connor Price|", "IMDB_ID"=>nil, "Language"=>"en", "Overview"=>"A girl named Lilly (Bailee Madison) is given her very own life-sized \"Really You\" doll which is named Lilly D.; because she is good at manipulating her dad. Lilly remains a spoiled brat, bragging about Lilly D, even going as far as ripping the leg off a friends doll, after the friend informs Lilly that \"Lilly D hates Lilly\". Soon after, strange events begin to occur which Lilly's mother accuses Lilly of doing; despite how Lilly maintains she is innocent, and that Lilly D is alive.", "ProductionCode"=>nil, "Rating"=>"8.0", "RatingCount"=>"1", "SeasonNumber"=>"1", "Writer"=>nil, "absolute_number"=>nil, "filename"=>"episodes/220441/3453441.jpg", "lastupdated"=>"1350772755", "seasonid"=>"393441", "seriesid"=>"220441"}, ...

注意Episode现在是Array种类型Hash

2 个答案:

答案 0 :(得分:1)

使用哈希键/值方法

而不是Enumerator#each,您可能希望使用Hash#each_keyHash#each_valueHash#each_pair来迭代哈希值。

答案 1 :(得分:1)

听起来像Rails'Array#wrap方法可以解决您的问题。我相信这应该有效:

Array.wrap(hash_data['Data']['Episode']).each do ...

文档here