如何从 savon 响应中解析属性
How to parse attribute from savon response
我正在底部发布我正在使用的 soap 响应。
我需要从 <t:Body BodyType="HTML">
中获取 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")
return 空白。
我怎样才能检索 BodyType
的值?
由于发布发出 secure/private 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>
命名空间确实可以搅浑水。
默认情况下,Nokogiri 将在根节点中查找命名空间声明,因此如果 xmlns:t
已在根节点中定义,t|Body
将起作用。
但是,因为它不是,所以您必须使用 collect_namespaces
告诉 Nokogiri 搜索文档并构建它找到的所有文档的散列。然后您可以将该散列传递给 search
、css
、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/"}
这将导致仅散列 s:Body
:
中的命名空间
我正在底部发布我正在使用的 soap 响应。
我需要从 <t:Body BodyType="HTML">
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")
return 空白。
我怎样才能检索 BodyType
的值?
由于发布发出 secure/private 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>
命名空间确实可以搅浑水。
默认情况下,Nokogiri 将在根节点中查找命名空间声明,因此如果 xmlns:t
已在根节点中定义,t|Body
将起作用。
但是,因为它不是,所以您必须使用 collect_namespaces
告诉 Nokogiri 搜索文档并构建它找到的所有文档的散列。然后您可以将该散列传递给 search
、css
、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/"}
这将导致仅散列 s:Body
: