所以我有这个货币 .xml 文件:
http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml
现在,我想知道,我怎样才能让我的 rails 应用程序读取它?我什至必须把它放在哪里以及如何包含它?
我基本上是在做一个货币汇率计算器。
我要让下拉菜单中出现 .xml 表中的货币名称并且可以使用。
所以我有这个货币 .xml 文件:
http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml
现在,我想知道,我怎样才能让我的 rails 应用程序读取它?我什至必须把它放在哪里以及如何包含它?
我基本上是在做一个货币汇率计算器。
我要让下拉菜单中出现 .xml 表中的货币名称并且可以使用。
首先,您必须能够读取该文件——我假设您想要该站点的最新版本,因此您将发出 HTTP 请求(否则,只需将文件存储在您的应用程序中的任何位置,然后File.read
用相对路径阅读)。我在这里使用Net::HTTP
,但你可以使用HTTParty
或任何你喜欢的。
看起来它每天都在变化,所以也许您只想每天发出一个 HTTP 请求并将文件与时间戳一起缓存在某处。
假设您的应用程序中有一个目录,称为rates
我们存储缓存的 xml 文件的位置,功能的核心可能如下所示(有点笨拙,但我希望行为明显):
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,那么这就是您的朋友。对于任何更复杂的东西,您将需要寻找一个 XML 库,例如Nokogiri
. 正在挖掘哈希以["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
某种不错的方式使异常无效并处理异常……比抱歉更安全。