如何将XML转换为Rails中的哈希? [英] How do I convert XML into a hash in Rails?

查看:113
本文介绍了如何将XML转换为Rails中的哈希?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将XML体转换为Ruby中的哈希?



我有一个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 datetime字符串转换为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}
]
}
}

我可以使用 parse in_time_zone 方法转换单个日期时间: / p>

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

但我不太清楚在将XML转换成哈希时解析时间的最佳方法。



<我很感激任何建议。谢谢!



编辑



将datetime字符串转换为Rails DateTime对象的代码是错误的。这将解析xml datetime字符串到系统的时区偏移量,然后将该时间转换为用户的时区。正确的代码是:



Time.zone.parse(xml_datetime)



如果用户具有与系统不同的时区,则会将用户的时区偏移添加到原始datetime字符串。有一个关于如何在这里启用用户时区偏好的Railscast: http:/ /railscasts.com/episodes/106-time-zones-in-rails-2-1

解决方案

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



当我切换到Ruby时,最终使用了Nokogiri,并发现它是非常容易用于解析HTML和XML。这很容易,我认为在CSS或XPath选择器方面,不要错过一个XML到散列转换器。

 需要'ap'
需要'date'
需要'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'做| 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

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

,输出如下:

  DateTime 
时间
[
[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对象,以显示可以使用。


How do I convert an XML body to a hash in Ruby?

I have an XML body which I'd like to parse into a hash

<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>

I'd like to convert it into a hash like this:

{ :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" }
        ]
    } 
}

Ideally, the tags would convert to snake_case symbols and become keys within the hash.

Also, the datetimes are missing their time zone offsets. They are in the local time zone (not UTC). So I'd like to parse it to show the local offset and then convert the xml datetime strings into Rails DateTime objects. The resulting array would be something like:

{ :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 }
        ]
    } 
}

I was able to convert a single datetime with the parse and in_time_zone methods this way:

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

But I'm not quite sure the best way to parse the times while converting the XML into a hash.

I'd appreciate any advice. Thanks!

Edit

The code for converting the datetime string into a Rails DateTime object is wrong. That will parse the xml datetime string to the system's timezone offset and then convert that time to the user's timezone. The correct code is:

Time.zone.parse(xml_datetime)

If the user has a different time zone other than the system, this will add the user's time zone offset to the original datetime string. There's a Railscast on how to enable user timezone preferences here: http://railscasts.com/episodes/106-time-zones-in-rails-2-1.

解决方案

I used to use XML::Simple in Perl because parsing XML using Perl was a PITA.

When I switched to Ruby I ended up using Nokogiri, and found it to be very easy to use for parsing HTML and XML. It's so easy that I think in terms of CSS or XPath selectors and don't miss a XML-to-hash converter.

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]

with the output looking like:

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
    }
]

The time values are deliberately parsed into DateTime and Time objects to show that either could be used.

这篇关于如何将XML转换为Rails中的哈希?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆