如何从savon响应中解析属性

时间:2016-09-16 17:58:29

标签: ruby nokogiri savon

我发布了我在底部工作的肥皂回复 我需要从BodyType="HTML"

获取<t:Body BodyType="HTML">属性

执行response.body会将整个内容转换为哈希值,并且没有BodyType="HTML"的迹象。

执行response.doc.css("t|Body")会生成错误:Undefined namespace prefix: //t:Body (Nokogiri::XML::XPath::SyntaxError),因为我在XML中没有看到该命名空间声明。

执行response.doc.css("Body")返回空白。

我该怎么做才能检索BodyType的价值?

由于发布发出安全/私有soap请求的代码没有意义,我发布了一些从平面文件中读取XML的基本代码:

require 'savon'
require 'active_support/core_ext/hash/conversions'
require 'nokogiri'

@doc = Nokogiri::XML(File.open("tmp.xml"))
puts @doc.css("t|Body")

这是XML:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="15" MinorVersion="1" MajorBuildNumber="629" MinorBuildNumber="8" Version="V2016_07_13"/>
  </s:Header>
  <s:Body>
    <m:GetItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:GetItemResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:Items>
            <t:Message>
              <t:ItemId Id="AAMkADE2NjQyMjVlLWNhY2UtNDNiMS04MzgxLWZiNzEyNzA0NDgwNQBGAAAAAACLt5QBAQ/GRYv+vEXkY5vLBwA6ksGFFTICTbjFW6e9FfRGAAAAAAEMAAA6ksGFFTICTbjFW6e9FfRGAAAu8FruAAA=" ChangeKey="CQAAABYAAAA6ksGFFTICTbjFW6e9FfRGAAAu9iR3"/>
              <t:ParentFolderId Id="AAMkADE2NjQyMjVlLWNhY2UtNDNiMS04MzgxLWZiNzEyNzA0NDgwNQAuAAAAAACLt5QBAQ/GRYv+vEXkY5vLAQA6ksGFFTICTbjFW6e9FfRGAAAAAAEMAAA=" ChangeKey="AQAAAA=="/>
              <t:ItemClass>IPM.Note</t:ItemClass>
              <t:Subject>From test</t:Subject>
              <t:Sensitivity>Normal</t:Sensitivity>
              <t:Body BodyType="HTML">Hello world</t:Body>
            </t:Message>
          </m:Items>
        </m:GetItemResponseMessage>
      </m:ResponseMessages>
    </m:GetItemResponse>
  </s:Body>
</s:Envelope>

1 个答案:

答案 0 :(得分:1)

命名空间真的会让水变得混乱。

默认情况下,Nokogiri会在根节点中查找名称空间声明,因此如果在根节点中定义了ChromeOptions options = new ChromeOptions(); options.addArguments("load-extension=" + ext_folder); WebDriver driver = new ChromeDriver(options); driver.get("chrome://extensions-frame/"); driver.findElement(By.xpath("//a[@class='extension-commands-config']")).click(); driver.findElement(By.xpath("//span[@class='command-shortcut-text']")).sendKeys(Keys.CONTROL + "m"); driver.findElement(By.id("extension-commands-dismiss")).click(); driver.findElement(By.tagName("body")).sendKeys(Keys.CONTROL + "m"); t|Body将起作用。

但是,因为它不是,你必须使用collect_namespaces告诉Nokogiri搜索文档并构建它找到的所有文件的哈希值。然后,您可以将该哈希值传递给xmlns:tsearchcss或任何搜索方法:

at

如果您阅读了require 'nokogiri' doc = Nokogiri::XML(<<EOT) <?xml version="1.0" encoding="utf-8"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <m:GetItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Message> <t:Body BodyType="HTML">Hello world</t:Body> </t:Message> </m:GetItemResponse> </s:Body> </s:Envelope> EOT ns = doc.collect_namespaces # => {"xmlns:s"=>"http://schemas.xmlsoap.org/soap/envelope/", "xmlns:t"=>"http://schemas.microsoft.com/exchange/services/2006/types", "xmlns:m"=>"http://schemas.microsoft.com/exchange/services/2006/messages"} doc.at("t|Body", ns)['BodyType'] # => "HTML" 的文档,那么您会发现,返回的密钥可能会覆盖以前找到的声明,这是一个潜在的问题。如果出现这样的问题,您可以通过找到collect_namespaces节点来解决这个问题,然后找到它的第一个子元素,然后收集命名空间:

s:Body

这将导致ns = doc.at('s|Body').first_element_child.namespaces # => {"xmlns:m"=>"http://schemas.microsoft.com/exchange/services/2006/messages", "xmlns:t"=>"http://schemas.microsoft.com/exchange/services/2006/types", "xmlns:s"=>"http://schemas.xmlsoap.org/soap/envelope/"} 中只有名称空间的哈希: