将.xml文件包含到rails并使用它

时间:2013-10-28 17:09:48

标签: ruby-on-rails xml

所以我有这种货币.xml文件:

http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml

现在,我想知道,我怎样才能让我的rails应用程序读取它?我甚至要把它放在哪里?如何包含它? 我基本上是在制作货币汇率计算器。

我打算在下拉菜单中显示.xml表中的货币名称,并且可以使用。

1 个答案:

答案 0 :(得分:2)

首先,您必须能够读取该文件 - 我假设您需要该网站的最新信息,因此您将发出HTTP请求(否则,只需将文件存储在任何位置)您的应用并使用相对路径File.read阅读。我在这里使用Net::HTTP,但您可以使用HTTParty或您喜欢的任何内容。

它看起来每天都在变化,所以也许你只想每天发一个HTTP请求并将文件缓存到某个地方以及时间戳。

假设您的应用程序中有一个名为rates的目录,我们存储缓存的xml文件,功能的核心可能就像这样(有点笨重,但我希望行为明显):< / p>

def get_rates
  today_path = Rails.root.join 'rates', "#{Date.today.to_s}.xml"

  xml_content = if File.exists? today_path
                  # Read it from local storage
                  File.read today_path
                else
                  # Go get it and store it!
                  xml = Net::HTTP.get URI 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'
                  File.write today_path, xml
                  xml
                end

  # Now convert that XML to a hash. Lots of ways to do this, but this is very simple xml.
  currency_list = Hash.from_xml(xml_content)["Envelope"]["Cube"]["Cube"]["Cube"]

  # Now currency_list is an Array of hashes e.g. [{"currency"=>"USD", "rate"=>"1.3784"}, ...]
  # Let's say you want a single hash like "USD" => "1.3784", you could do a conversion like this
  Hash[currency_list.map &:values]
end

重要的部分是Hash.from_xml。如果您的XML基本上是键/值对,那么这就是您的朋友。对于任何更复杂的事情,您将需要查找像Nokogiri这样的XML库。 ["Envelope"]["Cube"]["Cube"]["Cube"]正在挖掘哈希以找到重要部分。

现在,你可以看到它对XML结构中的任何变化有多敏感,你应该使端点可配置,并且该散列可能小到足以缓存在内存中,但是这是基本的想法。

要从哈希中获取您的货币列表,请说get_rates.keys

只要您了解正在发生的事情,就可以将其缩小:

def get_rates
  today_path = Rails.root.join 'rates', "#{Date.today.to_s}.xml"

  Hash[Hash.from_xml(if File.exists? today_path
                       File.read today_path
                     else
                       xml = Net::HTTP.get URI 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'
                       File.write today_path, xml
                       xml
                     end)["Envelope"]["Cube"]["Cube"]["Cube"].map &:values]
end

如果您确实选择缓存xml,您可能也希望自动清除旧版本的缓存XML文件。如果要缓存其他转换列表,请考虑从URI自动派生的命名方案,例如eurofxref-daily-2013-10-28.xml

编辑:假设您要将转换后的xml缓存在内存中 - 为什么不呢!

module CurrencyRetrieval
  def get_rates
    if defined?(@@rates_retrieved) && (@@rates_retrieved == Date.today)
      @@rates
    else
      @@rates_retrieved = Date.today
      @@rates = Hash[Hash.from_xml(Net::HTTP.get URI 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml')["Envelope"]["Cube"]["Cube"]["Cube"].map &:values]
    end
  end
end

现在只需include CurrencyRetrieval,只要你需要它,你就是金色的。 @@rates@@rates_retrieved将作为类变量存储在您包含此模块的任何类中。您必须测试生产设置中的调用之间是否存在这种情况(否则会回退到基于文件的方法或将这些值存储在其他位置)。

请注意,如果XML结构发生更改,或者XML今天不可用,您将需要使@@rates无效并以一种不错的方式处理异常......比抱歉更安全。