这是我简化的myXML:
<?xml version="1.0" encoding="utf-8"?>
<ShipmentRequest>
<Message>
<MemberId>A00000001</MemberId>
<MemberName>Bruce</MemberName>
<Line>
<LineNumber>3.1</LineNumber>
<Item>fruit-004</Item>
<Description>Peach</Description>
</Line>
<Line>
<LineNumber>4.1</LineNumber>
<Item>fruit-001</Item>
<Description>Peach</Description>
</Line>
</Message>
</ShipmentRequest>
当我使用Crack gem myHash
解析它时:
{
"MemberId"=>"A00000001",
"MemberName"=>"Bruce",
"Line"=>[
{"LineNumber"=>"3.1", "Item"=>"A0001", "Description"=>"Apple"},
{"LineNumber"=>"4.1", "Item"=>"A0002", "Description"=>"Peach"}
]
}
Crack gem将哈希值Line
创建为数组,因为myXML中有两个<Line>
个节点。但是如果myXML只包含一个<Line>
节点,则Crack gem不会将其解析为数组:
{
"MemberId"=>"ABC0001",
"MemberName"=>"Alan",
"Line"=> {"LineNumber"=>"4.1", "Item"=>"fruit-004", "Description"=>"Apple"}
}
无论是否只有一个节点,我都希望它仍然是一个数组:
{
"MemberId"=>"ABC0001",
"MemberName"=>"Alan",
"Line"=> [{"LineNumber"=>"4.1", "Item"=>"fruit-004", "Description"=>"Apple"}]
}
答案 0 :(得分:3)
将XML文档转换为哈希后,您可以执行以下操作:
myHash["Line"] = [myHash["Line"]] if myHash["Line"].kind_of?(Hash)
它将确保Line
节点将包装在Array中。
答案 1 :(得分:1)
问题是,你依靠代码来做你真正应该做的事情。 Crack不知道您希望单个节点成为单个元素的数组,而这种行为会让您在尝试深入了解该部分数据时变得更加困难。
解析XML并不难,而且,通过自己解析它,你会知道会发生什么,并且会避免处理“有时它是一个数组,有时它不是”由Crack返回的麻烦。
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="utf-8"?>
<ShipmentRequest>
<Message>
<MemberId>A00000001</MemberId>
<MemberName>Bruce</MemberName>
<Line>
<LineNumber>3.1</LineNumber>
<Item>fruit-004</Item>
<Description>Peach</Description>
</Line>
<Line>
<LineNumber>4.1</LineNumber>
<Item>fruit-001</Item>
<Description>Peach</Description>
</Line>
</Message>
</ShipmentRequest>
EOT
设置DOM,因此可以导航:
hash = {}
message = doc.at('Message')
hash[:member_id] = message.at('MemberId').text
hash[:member_name] = message.at('MemberName').text
lines = message.search('Line').map do |line|
line_number = line.at('LineNumber').text
item = line.at('Item').text
description = line.at('Description').text
{
:line_number => line_number,
:item => item,
:description => description
}
end
hash[:lines] = lines
message = doc.at('Message')
找到第一个<Message>
节点。message.at('MemberId').text
找到<MemberID>
内的第一个<Message>
节点。message.at('MemberName').text
与上述步骤类似。message.search('Line')
查找<Line>
内的所有<Message>
个节点。从这些描述中你可以弄清楚其余部分。
运行后,hash
看起来像:
{:member_id=>"A00000001",
:member_name=>"Bruce",
:lines=>
[{:line_number=>"3.1", :item=>"fruit-004", :description=>"Peach"},
{:line_number=>"4.1", :item=>"fruit-001", :description=>"Peach"}]}
如果我从XML中删除其中一个<Line>
块,然后重新运行,我会得到:
{:member_id=>"A00000001",
:member_name=>"Bruce",
:lines=>[{:line_number=>"3.1", :item=>"fruit-004", :description=>"Peach"}]}
使用search
定位<Line>
节点就是诀窍。 search
返回一个NodeSet,它类似于一个数组,所以通过使用map
迭代它,它将返回一个内容为<Line>
个标签的哈希数组。
Nokogiri是解析HTML和XML的绝佳工具,然后允许我们搜索,添加,更改或删除节点。它支持CSS和XPath访问器,所以如果你习惯了jQuery或CSS如何工作,或者XPath表达式,你将会快速启动并运行。 Nokogiri的教程是学习它如何工作的良好起点。