Rails nokogiri 解析 XML 文件
Rails nokogiri parse XML file
我有点困惑:在网络上找不到用 nokogiri 解析 xml 的好例子...
我的数据示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<rows SessionGUID="6448680D1">
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote />
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>1</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-58</OfferName>
<PeriodMin>2</PeriodMin>
<PeriodMax>4</PeriodMax>
<PriceListDiscountCode>31087</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>41</Quantity>
<SupplierID>30</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>203.35</Price>
</row>
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote>[0451103079] Bosch,MTGC@0451103079</PriceListItemNote>
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>0</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-1303</OfferName>
<PeriodMin>3</PeriodMin>
<PeriodMax>5</PeriodMax>
<PriceListDiscountCode>102134</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>5</Quantity>
<SupplierID>666</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>172.99</Price>
</row>
</rows>
</root>
和ruby代码:
...
xml_doc = Nokogiri::XML(response.body)
parts = xml_doc.xpath('/root/rows/row')
在 xpath 的帮助下我可以做到这一点吗?还有如何获取这个零件对象(行)?
你走在正确的轨道上。 parts = xml_doc.xpath('/root/rows/row')
返回 NodeSet
即 <row>
元素的列表。
您可以使用 each
遍历它们或使用 parts[0]
、parts[1]
等行索引来访问特定行。然后,您可以在各个行上使用 xpath
获取子节点的值。
例如您可以为每个部分构建一个 AnalogueCode
列表:
codes = []
parts.each do |row|
codes << row.xpath('AnalogueCode').text
end
查看您正在处理的 XML 的完整示例,有 2 个问题阻止您的 XPath 匹配:
<root>
标签实际上不是 XML 的根元素,所以 /root/..
不匹配
XML 正在使用命名空间,因此您需要将这些包含在您的 XPath 中
所以有几个可能的解决方案:
使用 CSS 选择器而不是 the Tin Man
建议的 XPath(即使用 search
)
在 xml_doc = Nokogiri::XML(response.body)
之后执行 xml_doc.remove_namespaces!
然后使用 parts = xml_doc.xpath('//root/rows/row')
其中双斜杠是 XPath 语法来定位文档中任意位置的 root
节点
指定命名空间:
例如
xml_doc = Nokogiri::XML(response.body)
ns = xml_doc.collect_namespaces
parts = xml_doc.xpath('//xmlns:rows/xmlns:row', ns)
codes = []
parts.each do |row|
codes << xpath('xmlns:AnalogueCode', ns).text
end
我会选择 1. 或 2.:-)
首先,Nokogiri 支持 XPath AND CSS。我推荐使用 CSS 因为它更容易阅读:
doc.search('row')
将 return 文档中每个 <row>
的节点集。
等效的 XPath 是:
doc.search('//row')
...how to get this parts object (row)?
我不确定那是什么意思,但是如果您想访问 <row>
中的各个元素,可以通过多种方式轻松完成。
如果您只希望每个行节点中有一个节点:
doc.search('row Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
doc.search('//row/Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
如果您只想要第一个这样的出现,请使用 at
,这相当于 search(...).first
:
doc.at('row Price').to_xml
# => "<Price>203.35</Price>"
通常我们想要遍历多个块和return找到的数据的哈希数组:
row_hash = doc.search('row').map{ |row|
{
AnalogueCode: row.at('AnalogueCode').text,
Price: row.at('Price').text,
}
}
row_hash
# => [{:AnalogueCode=>"0451103079", :Price=>"203.35"},
# {:AnalogueCode=>"0451103079", :Price=>"172.99"}]
这些是 Nokogiri 教程中 ALL 的内容,并且在 Stack Overflow 上已多次回答,因此请花时间阅读和搜索。
我有点困惑:在网络上找不到用 nokogiri 解析 xml 的好例子...
我的数据示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<rows SessionGUID="6448680D1">
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote />
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>1</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-58</OfferName>
<PeriodMin>2</PeriodMin>
<PeriodMax>4</PeriodMax>
<PriceListDiscountCode>31087</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>41</Quantity>
<SupplierID>30</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>203.35</Price>
</row>
<row>
<AnalogueCode>0451103079</AnalogueCode>
<AnalogueCodeAsIs>0451103079</AnalogueCodeAsIs>
<AnalogueManufacturerName>BOSCH</AnalogueManufacturerName>
<AnalogueWeight>0.000</AnalogueWeight>
<CodeAsIs>OC90</CodeAsIs>
<DeliveryVariantPriceAKiloForClientDescription />
<DeliveryVariantPriceAKiloForClientPrice>0.00</DeliveryVariantPriceAKiloForClientPrice>
<DeliveryVariantPriceNote />
<PriceListItemDescription />
<PriceListItemNote>[0451103079] Bosch,MTGC@0451103079</PriceListItemNote>
<IsAvailability>1</IsAvailability>
<IsCross>1</IsCross>
<LotBase>1</LotBase>
<LotType>0</LotType>
<ManufacturerName>KNECHT/MAHLE</ManufacturerName>
<OfferName>MSC-STC-1303</OfferName>
<PeriodMin>3</PeriodMin>
<PeriodMax>5</PeriodMax>
<PriceListDiscountCode>102134</PriceListDiscountCode>
<ProductName>Фильтр масляный</ProductName>
<Quantity>5</Quantity>
<SupplierID>666</SupplierID>
<GroupTitle>Замена</GroupTitle>
<Price>172.99</Price>
</row>
</rows>
</root>
和ruby代码:
...
xml_doc = Nokogiri::XML(response.body)
parts = xml_doc.xpath('/root/rows/row')
在 xpath 的帮助下我可以做到这一点吗?还有如何获取这个零件对象(行)?
你走在正确的轨道上。 parts = xml_doc.xpath('/root/rows/row')
返回 NodeSet
即 <row>
元素的列表。
您可以使用 each
遍历它们或使用 parts[0]
、parts[1]
等行索引来访问特定行。然后,您可以在各个行上使用 xpath
获取子节点的值。
例如您可以为每个部分构建一个 AnalogueCode
列表:
codes = []
parts.each do |row|
codes << row.xpath('AnalogueCode').text
end
查看您正在处理的 XML 的完整示例,有 2 个问题阻止您的 XPath 匹配:
<root>
标签实际上不是 XML 的根元素,所以/root/..
不匹配XML 正在使用命名空间,因此您需要将这些包含在您的 XPath 中
所以有几个可能的解决方案:
使用 CSS 选择器而不是 the Tin Man
建议的 XPath(即使用 在
xml_doc = Nokogiri::XML(response.body)
之后执行xml_doc.remove_namespaces!
然后使用parts = xml_doc.xpath('//root/rows/row')
其中双斜杠是 XPath 语法来定位文档中任意位置的root
节点指定命名空间:
search
)
例如
xml_doc = Nokogiri::XML(response.body)
ns = xml_doc.collect_namespaces
parts = xml_doc.xpath('//xmlns:rows/xmlns:row', ns)
codes = []
parts.each do |row|
codes << xpath('xmlns:AnalogueCode', ns).text
end
我会选择 1. 或 2.:-)
首先,Nokogiri 支持 XPath AND CSS。我推荐使用 CSS 因为它更容易阅读:
doc.search('row')
将 return 文档中每个 <row>
的节点集。
等效的 XPath 是:
doc.search('//row')
...how to get this parts object (row)?
我不确定那是什么意思,但是如果您想访问 <row>
中的各个元素,可以通过多种方式轻松完成。
如果您只希望每个行节点中有一个节点:
doc.search('row Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
doc.search('//row/Price').map(&:to_xml)
# => ["<Price>203.35</Price>", "<Price>172.99</Price>"]
如果您只想要第一个这样的出现,请使用 at
,这相当于 search(...).first
:
doc.at('row Price').to_xml
# => "<Price>203.35</Price>"
通常我们想要遍历多个块和return找到的数据的哈希数组:
row_hash = doc.search('row').map{ |row|
{
AnalogueCode: row.at('AnalogueCode').text,
Price: row.at('Price').text,
}
}
row_hash
# => [{:AnalogueCode=>"0451103079", :Price=>"203.35"},
# {:AnalogueCode=>"0451103079", :Price=>"172.99"}]
这些是 Nokogiri 教程中 ALL 的内容,并且在 Stack Overflow 上已多次回答,因此请花时间阅读和搜索。