我试图用Nokogiri从XML中提取值。
我想在数组中分隔具有相同名称但不同xpath的子元素。这些元素是ProdA
,ProdB
。
目前我只是尝试打印子元素,但到目前为止我的代码只打印了#34; SDocument"而不是儿童元素。
目标是这样的数组:
array = [["2","8"], ["8","9"]]
这是代码:
#!/usr/bin/env ruby
require 'nokogiri'
doc = Nokogiri::XML(File.open("input.xml"))
a = doc.xpath("//SDocument").each do |n|
n if n.text?
end
puts a
这是XML:
<?xml version="1.0" encoding="UTF-8"?>
<Document-St-5>
<SDocument>
<ItemList>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>2</ProdA>
<ProdB>8</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_B>
<ItemElem>
<Item_Values>
<ProdA>8</ProdA>
<ProdB>9</ProdB>
</Item_Values>
</ItemElem>
</Items_B>
</ItemList>
</SDocument>
</Document-St-5>
有人可以指出我正确的方法吗?
更新
我真正想要的是在数组中存储SDocument
节点的所有唯一子元素的XPath以及具有多个节点的那些元素的XPath
出现,存储它们分组。但是如果可能的话,在不知道子项名称的情况下获取XPath,只能得到唯一的XPath。
例如:
子元素StName
和StCode
每个元素只有一个出现,那么到目前为止具有XPath的数组将是:
arr_Xpath = [ ["/Document-St-5/SDocument/StName"], ["/Document-St-5/SDocument/StCode"], ... ]
作为节点ProdA
的子节点的Items_A
节点具有以下XPath:
/Document-St-5/SDocument/ItemList/Items_A/ItemElem/Item_Values/ProdA
作为节点ProdA
的子节点的Items_B
节点具有以下XPath:
/Document-St-5/SDocument/ItemList/Items_B/ItemElem/Item_Values/ProdA
然后,子元素的唯一XPath数组将是(包括ProdB
节点的XPath):
arr_Xpath = [ "/Document-St-5/SDocument/StName",
"/Document-St-5/SDocument/StCode",
"/Document-St-5/SDocument/ItemList/Items_A/ItemElem/Item_Values/ProdA",
"/Document-St-5/SDocument/ItemList/Items_A/ItemElem/Item_Values/ProdB",
"/Document-St-5/SDocument/ItemList/Items_B/ItemElem/Item_Values/ProdA",
"/Document-St-5/SDocument/ItemList/Items_B/ItemElem/Item_Values/ProdB" ]
我认为,首先了解唯一的XPath,可以使用doc.xpath("..")
获取每个子元素的值并将它们分组
如果它有多个出现。所以,我想得到的最终数组是:
arr_Values = [ ["WERLJ01"], ["MEKLD"],["2","9"],["8","3"],["1"],["17"]]
其中:
arr_Values[0]
是包含StName
值arr_Values[1]
是包含StCode
值arr_Values[2]
是包含ProdA
所有Items_A
个节点子项的值的数组。arr_Values[3]
是包含ProdB
所有Items_A
个节点子项的值的数组。arr_Values[4]
是包含ProdA
所有Items_B
个节点子项的值的数组。arr_Values[5]
是包含ProdB
所有Items_B
个节点子项的值的数组。XML示例是:
<?xml version="1.0" encoding="UTF-8"?>
<Document-St-5>
<SDocument>
<StName>WERLJ01</StName>
<StCode>MEKLD</StCode>
<ItemList>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>2</ProdA>
<ProdB>8</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>9</ProdA>
<ProdB>3</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_B>
<ItemElem>
<Item_Values>
<ProdA>1</ProdA>
<ProdB>17</ProdB>
</Item_Values>
</ItemElem>
</Items_B>
</ItemList>
</SDocument>
</Document-St-5>
更新2:
锡人你好,它有效!这是什么意思&#34;%w&#34;和&#34;%w [element1 element2]&#34;?表单%w [...]是否接受超过2个元素?
我是Nokogiri的新手,我只提到Xpath,因为XML有200多个独特的子节点(独特的Xpath&#39; s),那么你建议我对所有子节点使用相同的CSS技术或者是否存在一种处理XML并执行相同操作的方法(在数组中将具有相同名称且具有相同Xpath的元素分组),而不知道子节点的名称?我想知道你建议我的方式。
再次感谢
答案 0 :(得分:0)
这是一种方式:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<Document-St-5>
<SDocument>
<ItemList>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>2</ProdA>
<ProdB>8</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_B>
<ItemElem>
<Item_Values>
<ProdA>8</ProdA>
<ProdB>9</ProdB>
</Item_Values>
</ItemElem>
</Items_B>
</ItemList>
</SDocument>
</Document-St-5>
EOT
data = doc.search('SDocument').map{ |node|
%w[ProdA ProdB].map{ |n| node.search(n).map(&:text) }
}
data # => [[["2", "8"], ["8", "9"]]]
它导致嵌套比你想要的更深,但它很接近。
可能更容易理解的一种不同的方式是:
data = doc.search('SDocument').map{ |node|
%w[A B].map{ |ab|
node.at("Items_#{ ab }").search('ProdA, ProdB').map(&:text)
}
}
嵌套比你指定的更深一层的原因是,我假设XML中会有多个<SDocument>
标签。如果没有,则可以稍微修改代码以返回数组,如您所知:
data = doc.search('Items_A, Items_B').map{ |node|
node.search('ProdA, ProdB').map(&:text)
}
data # => [["2", "8"], ["8", "9"]]
注意我正在使用CSS选择器,以便于指定我希望代码查看两个不同的节点,包括Items_A
和Items_B
,以及ProdA
和{ {1}}。
问题彻底改变后更新:
这是设置:
ProdB
以下是代码:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<Document-St-5>
<SDocument>
<StName>WERLJ01</StName>
<StCode>MEKLD</StCode>
<ItemList>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>2</ProdA>
<ProdB>8</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_A>
<ItemElem>
<Item_Values>
<ProdA>9</ProdA>
<ProdB>3</ProdB>
</Item_Values>
</ItemElem>
</Items_A>
<Items_B>
<ItemElem>
<Item_Values>
<ProdA>1</ProdA>
<ProdB>17</ProdB>
</Item_Values>
</ItemElem>
</Items_B>
</ItemList>
</SDocument>
</Document-St-5>
EOT
以下是捕获的内容:
data = %w[StName StCode].map{ |n| [doc.at(n).text] }
%w[ProdA ProdB].each do |prod|
data << doc.search('Items_A').map{ |item| item.at(prod).text }
end
%w[ProdA ProdB].each do |prod|
data << [doc.at("Items_B #{prod}").text]
end