簡體   English   中英

如何將XML轉換為Rails中的哈希?

[英]How do I convert XML into a hash in Rails?

如何在Ruby中將XML主體轉換為哈希?

我有一個XML體,我想解析成哈希

<soap:Body>
    <TimesInMyDAY>
        <TIME_DATA>
            <StartTime>2010-11-10T09:00:00</StartTime>
            <EndTime>2010-11-10T09:20:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T09:20:00</StartTime>
            <EndTime>2010-11-10T09:40:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T09:40:00</StartTime>
            <EndTime>2010-11-10T10:00:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T10:00:00</StartTime>
            <EndTime>2010-11-10T10:20:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T10:40:00</StartTime>
            <EndTime>2010-11-10T11:00:00</EndTime>
        </TIME_DATA>
    </TimesInMyDAY>
</soap:Body>

我想把它轉換成這樣的哈希:

{ :times_in_my_day => { 
    :time_data = > [
        {:start_time=>"2010-11-10T09:00:00", :end_time => "2010-11-10T09:20:00" },
        {:start_time=>"2010-11-10T09:20:00", :end_time => "2010-11-10T09:40:00" },
        {:start_time=>"2010-11-10T09:40:00", :end_time => "2010-11-10T10:00:00" },
        {:start_time=>"2010-11-10T10:00:00", :end_time => "2010-11-10T10:20:00" },
        {:start_time=>"2010-11-10T10:40:00", :end_time => "2010-11-10T11:00:00" }
        ]
    } 
}

理想情況下,標記會轉換為snake_case符號並成為哈希中的鍵。

此外,日期時間缺少其時區偏移。 它們位於當地時區(不是UTC)。 所以我想解析它以顯示本地偏移量,然后將xml日期時間字符串轉換為Rails DateTime對象。 結果數組將是這樣的:

{ :times_in_my_day => { 
    :time_data = > [
        {:start_time=>Wed Nov 10 09:00:00 -0800 2010, :end_time => Wed Nov 10 9:20:00 -0800 2010 },
        {:start_time=>Wed Nov 10 09:20:00 -0800 2010, :end_time => Wed Nov 10 9:40:00 -0800 2010 },
        {:start_time=>Wed Nov 10 09:40:00 -0800 2010, :end_time => Wed Nov 10 10:00:00 -0800 2010 },
        {:start_time=>Wed Nov 10 10:00:00 -0800 2010, :end_time => Wed Nov 10 10:20:00 -0800 2010 },
        {:start_time=>Wed Nov 10 10:40:00 -0800 2010, :end_time => Wed Nov 10 11:00:00 -0800 2010 }
        ]
    } 
}

我能夠通過這種方式使用parsein_time_zone方法轉換單個日期時間:

Time.parse(xml_datetime).in_time_zone(current_user.time_zone)

但是我不太確定在將XML轉換為哈希時解析時間的最佳方法。

我很感激任何建議。 謝謝!

編輯

將datetime字符串轉換為Rails DateTime對象的代碼是錯誤的。 這會將xml日期時間字符串解析為系統的時區偏移量,然后將該時間轉換為用戶的時區。 正確的代碼是:

Time.zone.parse(xml_datetime)

如果用戶具有不同於系統的時區,則會將用戶的時區偏移量添加到原始日期時間字符串。 有關如何在此處啟用用戶時區首選項的Railscast: http//railscasts.com/episodes/106-time-zones-in-rails-2-1

Hash.from_xml(xml)是解決此問題的簡單方法。 它的activesupport方法

我以前在Perl中使用XML :: Simple,因為使用Perl解析XML是一個PITA。

當我切換到Ruby時,我最終使用了Nokogiri,發現它非常容易用於解析HTML和XML。 我認為在CSS或XPath選擇器方面非常容易,並且不要錯過XML-to-hash轉換器。

require 'ap'
require 'date'
require 'time'
require 'nokogiri'

xml = %{
<soap:Body>
    <TimesInMyDAY>
        <TIME_DATA>
            <StartTime>2010-11-10T09:00:00</StartTime>
            <EndTime>2010-11-10T09:20:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T09:20:00</StartTime>
            <EndTime>2010-11-10T09:40:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T09:40:00</StartTime>
            <EndTime>2010-11-10T10:00:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T10:00:00</StartTime>
            <EndTime>2010-11-10T10:20:00</EndTime>
        </TIME_DATA>
        <TIME_DATA>
            <StartTime>2010-11-10T10:40:00</StartTime>
            <EndTime>2010-11-10T11:00:00</EndTime>
        </TIME_DATA>
    </TimesInMyDAY>
</soap:Body>
}

time_data = []

doc = Nokogiri::XML(xml)
doc.search('//TIME_DATA').each do |t|
  start_time = t.at('StartTime').inner_text
  end_time = t.at('EndTime').inner_text
  time_data << {
    :start_time => DateTime.parse(start_time),
    :end_time   => Time.parse(end_time)
  }
end

puts time_data.first[:start_time].class
puts time_data.first[:end_time].class
ap time_data[0, 2]

輸出看起來像:

DateTime
Time
[
    [0] {
        :start_time => #<DateTime: 2010-11-10T09:00:00+00:00 (19644087/8,0/1,2299161)>,
          :end_time => 2010-11-10 09:20:00 -0700
    },
    [1] {
        :start_time => #<DateTime: 2010-11-10T09:20:00+00:00 (22099598/9,0/1,2299161)>,
          :end_time => 2010-11-10 09:40:00 -0700
    }
]

故意將時間值解析為DateTime和Time對象,以顯示可以使用其中任何一個。

ActiveSupport添加了一個Hash.from_xml ,它在一次調用中進行轉換。 另一個問題描述: https//stackoverflow.com/a/7488299/937595

例:

require 'open-uri'
remote_xml_file = "https://www.example.com/some_file.xml"
data = Hash.from_xml(open(remote_xml_file))

最初的問題是在前一段時間被問到的,但我找到了比使用Nokogiri並在XML中搜索特定名稱更簡單的解決方案。

Nori.parse(your_xml)將XML解析為散列,並且鍵將與XML項具有相同的名稱。

如果你不介意使用寶石,那么破解就可以了。

Crack對XML進行哈希處理,然后您可以循環生成的哈希以規范化日期時間。

編輯使用REXML,你可以嘗試以下(應該接近工作,但我沒有訪問終端,所以它可能需要一些調整):

require 'rexml/document'
arr = []
doc = REXML::XPath.first(REXML::Document.new(xml), "//soap:Body/TimesInMyDAY").text
REXML::XPath.each(doc, "//TIME_DATA") do |el|
  start = REXML::XPath.first(el, "//StartTime").text
  end = REXML::XPath.first(el, "//EndTime").text
  arr.push({:start_time => Time.parse(start).in_time_zone(current_user.time_zone), :end_time => Time.parse(end).in_time_zone(current_user.time_zone)})
end

hash = { :times_in_my_day => { :time_data => arr } }

當然,這假設結構始終是相同的,並且您發布的示例並非為簡單起見而設計(通常是示例)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM