Ruby 如何从XML文件中获取多个属性?
我有一个XML文件:Ruby 如何从XML文件中获取多个属性?,ruby,xml,nokogiri,Ruby,Xml,Nokogiri,我有一个XML文件: <One> <Document Count="1"> <Customer Id="1" Type="0"/> <Passengers> <Passenger Seq="1" Id="13" Name="Test Name"/> <Passenger Seq="2" Id="14" Name="Test Name4"/> </Passengers&
<One>
<Document Count="1">
<Customer Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="13" Name="Test Name"/>
<Passenger Seq="2" Id="14" Name="Test Name4"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="16" Name="Test Name10"/>
<Passenger Seq="2" Id="18" Name="Test Name30"/>
</Passengers>
</Document>
</One>
...
<Two>
<Document Count="1">
<User Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="123" Name="Test Name"/>
<Passenger Seq="2" Id="124" Name="Test Name2"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="1130" Name="Test Name123"/>
<Passenger Seq="2" Id="1131" Name="Test Name34342"/>
</Passengers>
</Document>
</Two>
我该怎么做呢?只要更换线路就行了
hash[:id] = pass['Name'] #???
与
只要您有一个有效的XML文件,它就可以工作
问题中的XML片段无效,原因有两个:
- 介于
和
之间的
(我想这是故意的,与您的真实数据无关)..
- 您的XML没有根元素。目前您有两个“根”,元素
和
。如果这就是真正的XML文件的组成方式,我认为Nokogiri将只读取第一个节点
array = []
Nokogiri::XML(File.open(file.xml)).xpath("//Document//Passengers//Passenger").each do |x|
hash = {}
x.attributes.each do |attribute| # loop through all attributes in the matches found
hash[attribute[1].name.to_sym] = attribute[1].value
end
array << hash
end
我会这样做:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<xml>
<One>
<Document Count="1">
<Customer Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="13" Name="Test Name"/>
<Passenger Seq="2" Id="14" Name="Test Name4"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="16" Name="Test Name10"/>
<Passenger Seq="2" Id="18" Name="Test Name30"/>
</Passengers>
</Document>
</One>
<Two>
<Document Count="1">
<User Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="123" Name="Test Name"/>
<Passenger Seq="2" Id="124" Name="Test Name2"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="1130" Name="Test Name123"/>
<Passenger Seq="2" Id="1131" Name="Test Name34342"/>
</Passengers>
</Document>
</Two>
</xml>
EOT
以下是array
的外观:
array
# => [{:id=>"13", :name=>"Test Name"},
# {:id=>"14", :name=>"Test Name4"},
# {:id=>"16", :name=>"Test Name10"},
# {:id=>"18", :name=>"Test Name30"},
# {:id=>"123", :name=>"Test Name"},
# {:id=>"124", :name=>"Test Name2"},
# {:id=>"1130", :name=>"Test Name123"},
# {:id=>"1131", :name=>"Test Name34342"}]
我正在使用CSS选择器。因为我想要所有的“乘客”节点,所以搜索变得很容易,不需要深入父节点链
不过,哈希数组的使用/重用非常困难。如果:id
中没有冲突的可能性,我建议使用常规哈希:
hash = doc.search('Passenger').map{ |node| [node['Id'], node['Name']] }.to_h
hash
# => {"13"=>"Test Name",
# "14"=>"Test Name4",
# "16"=>"Test Name10",
# "18"=>"Test Name30",
# "123"=>"Test Name",
# "124"=>"Test Name2",
# "1130"=>"Test Name123",
# "1131"=>"Test Name34342"}
如果需要动态跟踪乘客节点的所有参数,无论何时添加新参数或删除旧参数:
hash = doc.search('Passenger').map{ |node|
[
node['Id'],
node.attribute_nodes.map{ |a|
[a.name, a.value]
}.to_h
]
}.to_h
hash
# => {"13"=>{"Seq"=>"1", "Id"=>"13", "Name"=>"Test Name"},
# "14"=>{"Seq"=>"2", "Id"=>"14", "Name"=>"Test Name4"},
# "16"=>{"Seq"=>"1", "Id"=>"16", "Name"=>"Test Name10"},
# "18"=>{"Seq"=>"2", "Id"=>"18", "Name"=>"Test Name30"},
# "123"=>{"Seq"=>"1", "Id"=>"123", "Name"=>"Test Name"},
# "124"=>{"Seq"=>"2", "Id"=>"124", "Name"=>"Test Name2"},
# "1130"=>{"Seq"=>"1", "Id"=>"1130", "Name"=>"Test Name123"},
# "1131"=>{"Seq"=>"2", "Id"=>"1131", "Name"=>"Test Name34342"}}
基本上,这将创建节点的散列表示,它可以是好的,也可以是坏的,这取决于您试图对数据执行的操作。您是对的。实际上一切都很好。我的脚本中确实有错误,但在stackoverflow上我写的都是正确的。“您的XML没有根元素。目前您有两个“根”,元素和。”这是因为XML格式不正确。XML需要根节点。谢谢。我现在找到了关于我的问题的正确答案。不要使用
“//文档//乘客//乘客”
。正确的XPath应该是“//文档/乘客/乘客”
/
表示“从根开始在任何地方找到它”,因此您反复告诉解析器重新开始搜索。XML示例的格式不正确。XML需要一个根节点,而您有两个。要获取所有属性还是特定属性?如果属性发生更改,您是希望代码动态地反映这一点,还是应该将代码设置为静态,并且必须手动调整以获取更改?谢谢!这个方法帮助我删除了脚本中的许多字符串。解析XML/HTML一开始可能会让人困惑。我发现使用CSS选择器更容易,因为它们更可读,尽管XPath的功能更强。在代码中,在它们之间来回跳转是可以的。
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<xml>
<One>
<Document Count="1">
<Customer Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="13" Name="Test Name"/>
<Passenger Seq="2" Id="14" Name="Test Name4"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="16" Name="Test Name10"/>
<Passenger Seq="2" Id="18" Name="Test Name30"/>
</Passengers>
</Document>
</One>
<Two>
<Document Count="1">
<User Id="1" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="123" Name="Test Name"/>
<Passenger Seq="2" Id="124" Name="Test Name2"/>
</Passengers>
</Document>
<Document Count="2">
<Customer Id="2" Type="0"/>
<Passengers>
<Passenger Seq="1" Id="1130" Name="Test Name123"/>
<Passenger Seq="2" Id="1131" Name="Test Name34342"/>
</Passengers>
</Document>
</Two>
</xml>
EOT
array = doc.search('Passenger').map{ |node|
{
id: node['Id'],
name: node['Name']
}
}
array
# => [{:id=>"13", :name=>"Test Name"},
# {:id=>"14", :name=>"Test Name4"},
# {:id=>"16", :name=>"Test Name10"},
# {:id=>"18", :name=>"Test Name30"},
# {:id=>"123", :name=>"Test Name"},
# {:id=>"124", :name=>"Test Name2"},
# {:id=>"1130", :name=>"Test Name123"},
# {:id=>"1131", :name=>"Test Name34342"}]
hash = doc.search('Passenger').map{ |node| [node['Id'], node['Name']] }.to_h
hash
# => {"13"=>"Test Name",
# "14"=>"Test Name4",
# "16"=>"Test Name10",
# "18"=>"Test Name30",
# "123"=>"Test Name",
# "124"=>"Test Name2",
# "1130"=>"Test Name123",
# "1131"=>"Test Name34342"}
hash = doc.search('Passenger').map{ |node|
[
node['Id'],
node.attribute_nodes.map{ |a|
[a.name, a.value]
}.to_h
]
}.to_h
hash
# => {"13"=>{"Seq"=>"1", "Id"=>"13", "Name"=>"Test Name"},
# "14"=>{"Seq"=>"2", "Id"=>"14", "Name"=>"Test Name4"},
# "16"=>{"Seq"=>"1", "Id"=>"16", "Name"=>"Test Name10"},
# "18"=>{"Seq"=>"2", "Id"=>"18", "Name"=>"Test Name30"},
# "123"=>{"Seq"=>"1", "Id"=>"123", "Name"=>"Test Name"},
# "124"=>{"Seq"=>"2", "Id"=>"124", "Name"=>"Test Name2"},
# "1130"=>{"Seq"=>"1", "Id"=>"1130", "Name"=>"Test Name123"},
# "1131"=>{"Seq"=>"2", "Id"=>"1131", "Name"=>"Test Name34342"}}