Savon数组/哈希混淆

时间:2018-10-17 16:04:32

标签: ruby xml xml-parsing nokogiri savon

当savon解析xml

<MessageList>
  <TradeMessage ID="4850644"/>
  <TradeMessage ID="4850666"/>
  <TradeMessage ID="4850667"/>
  <TradeMessage ID="4850712"/>
</MessageList>

它返回哈希{MessageList: TradeMessage: [{@id: '123'},...,{@id: '456'}]}

但是如果xml会像

<MessageList>
  <TradeMessage ID="4850644"/>
</MessageList>

它将返回{MessageList: TradeMessage: {@id: '123'}}

因此我无法遍历消息列表,因为它可以是哈希或数组。

我的代码遍历数组:

t[:message_list][:trade_message].each do |m|
  TradeMessage.create(id: m[:@id])
end

在这种情况下该怎么办?我应该将xml解析器从默认的nokogiri更改为其他吗?

更新:我注意到,Hash.from_xml(string)将哈希相似地返回给savon-如果有多个标签,则返回数组;如果一个标签,则返回哈希。

我的决定:使用nokogiri文档来解析savon响应response.doc

2 个答案:

答案 0 :(得分:1)

如果这是Savon的默认行为,我建议您查看一下您获得的结果类型并从那里进行解析:

if t[:message_list][:trade_message].is_a?(Array) # or perhaps `t[:message_list][:trade_message].respond_to?(:each)`
  t[:message_list][:trade_message].each { |m| TradeMessage.create(id: m[:@id]) }
else
  TradeMessage.create(id: t[:message_list][:trade_message][:@id])
end

或者,您可以将结果包装在数组中(如果尚未包装的话),并进行类似的处理:

t[:message_list][:trade_message].is_a?(Array) ? t[:message_list][:trade_message] : [t[:message_list][:trade_message]]
t[:message_list][:trade_message].each { |m| TradeMessage.create(id: m[:@id]) }

宝石的奇怪行为。可能值得研究他们的文档,看看是否可以使用某些东西来改变这种行为。

如果没有,希望对您有所帮助。如果您有任何疑问,请告诉我。

答案 1 :(得分:1)

您可以使用Ruby的splat运算符。它将始终返回一个数组。请参见下面的极端示例。

require 'awesome_print'

def return_array(elements)
  return *elements
end

ap return_array([:a, :b, :c])
ap return_array(:d)