繁体   English   中英

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>

和红宝石代码:

...
xml_doc  = Nokogiri::XML(response.body)
parts = xml_doc.xpath('/root/rows/row')

借助xpath我可以做到这一点? 还如何获取该零件对象(行)?

首先,Nokogiri支持XPath CSS。 我建议使用CSS,因为它更容易阅读:

doc.search('row')

将返回文档中每个<row>的NodeSet。

等效的XPath为:

doc.search('//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>"

通常,我们要迭代多个块并返回找到的数据的哈希数组:

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的教程,并在堆栈溢出这里回答很多次,所以花时间阅读和搜索的时间。

您走在正确的轨道上。 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的完整示例,有两个问题导致XPath无法匹配:

  1. <root>标记实际上不是XML的根元素,因此/root/..不匹配

  2. XML使用的是名称空间,因此您需要将其包含在XPath中

因此,有两种可能的解决方案:

  1. 使用CSS选择器,而不是Tin Man建议的XPath(即,使用search

  2. xml_doc = Nokogiri::XML(response.body)执行xml_doc.remove_namespaces! 然后使用parts = xml_doc.xpath('//root/rows/row') ,其中双斜杠是XPath语法,以在文档中的任何位置定位root

  3. 指定名称空间:

例如

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。:-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM