【问题标题】:Nokogiri::XML parse value based on another XML attribute's valueNokogiri::XML 解析值基于另一个 XML 属性的值
【发布时间】:2017-04-26 08:49:45
【问题描述】:

使用 Nokogiri::XML 如何根据另一个属性检索一个属性的值?

XML 文件:

  <RateReplyDetails>
    <ServiceType>INT</ServiceType>
    <Price>1.0</Price>
  </RateReplyDetails>
  <RateReplyDetails>
    <ServiceType>LOCAL</ServiceType>
    <Price>2.0</Price>
  </RateReplyDetails>

我想检索 LOCAL ServiceType 的价格,即 2.0

我可以在没有任何条件的情况下取值:

rated_shipment.at('RateReplyDetails/Price').text

也许我可以这样做:

if rated_shipment.at('RateReplyDetails/ServiceType').text == "LOCAL"
  rated_shipment.at('RateReplyDetails/Price').text

但是有什么优雅而干净的方式吗?

【问题讨论】:

    标签: ruby-on-rails ruby nokogiri


    【解决方案1】:

    我会这样做:

    require 'nokogiri'
    
    doc = Nokogiri::XML(<<EOT)
    <xml>
     <RateReplyDetails>
        <ServiceType>INT</ServiceType>
        <Price>1.0</Price>
      </RateReplyDetails>
      <RateReplyDetails>
        <ServiceType>LOCAL</ServiceType>
        <Price>2.0</Price>
      </RateReplyDetails>
    </xml>
    EOT
    
    service_type = doc.at('//RateReplyDetails/*[text() = "LOCAL"]')
    service_type.name # => "ServiceType"
    

    '//RateReplyDetails/*[text() = "LOCAL"]' 是一个 XPath 选择器,它查找包含等于 "LOCAL" 的文本节点的 &lt; RateReplyDetails&gt; 节点并返回包含文本的节点,即 &lt;ServiceType&gt; 节点。

    service_type.next_element.text # => "2.0"
    

    一旦我们发现查看下一个元素并获取其文本很容易。

    【讨论】:

      【解决方案2】:

      试试看,content是xml内容字符串。

      doc = Nokogiri::HTML(content)
      doc.at('servicetype:contains("INT")').next_element.content
      
      [16] pry(main)> 
      doc.at('servicetype:contains("INT")').next_element.content
      => "1.0"
      [17] pry(main)> 
      doc.at('servicetype:contains("LOCAL")').next_element.content
      => "2.0"
      

      我已经测试过了,它工作正常。

      【讨论】:

      • 在选择器中使用 CSS contains 时要小心,因为它是子字符串匹配,这意味着它将匹配字符串中任何位置的“INT”或“LOCAL”,可能会导致错误-正匹配。
      • 这对我也应该有用,因为我的文字在那里非常独特。我选择了第一个回答和正确的答案作为答案,但这也应该有效。谢谢大家
      • @theTinMan 谢谢你的提醒,其实我知道这个问题,在我粘贴这个答案之前,我尝试过你之前的方法,但是失败了,现在我知道了使用text 的正确方法了.谢谢。
      【解决方案3】:

      完全在 XPath 中:

      rated_shipment.at('//RateReplyDetails[ServiceType="LOCAL"]/Price/text()').to_s
      # => "2.0"
      

      编辑:

      对我没用

      完整的代码证明它确实有效:

      #!/usr/bin/env ruby
      require 'nokogiri'
      rated_shipment = Nokogiri::XML(DATA)
      puts rated_shipment.at('//RateReplyDetails[ServiceType="LOCAL"]/Price/text()').to_s
      __END__
      <xml>
       <RateReplyDetails>
          <ServiceType>INT</ServiceType>
          <Price>1.0</Price>
        </RateReplyDetails>
        <RateReplyDetails>
          <ServiceType>LOCAL</ServiceType>
          <Price>2.0</Price>
        </RateReplyDetails>
      </xml>
      

      (输出2.0。)如果它不起作用,那是因为您的文件内容与您的OP不匹配。

      【讨论】:

      • 它对我不起作用 - 搜索后必须去找父母
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      • 2015-09-04
      • 1970-01-01
      相关资源
      最近更新 更多