2016-09-16 6 views
0

Я отправляю ответ на мыло, с которым я работаю внизу.
мне нужно, чтобы захватить атрибут BodyType="HTML" из <t:Body BodyType="HTML">Как разобрать атрибут из ответа савона

Doing response.body превращает все вещи в хэш, и нет никаких признаков BodyType="HTML" в этом.

Выполнение response.doc.css("t|Body") создает ошибку: Undefined namespace prefix: //t:Body (Nokogiri::XML::XPath::SyntaxError), потому что я не вижу этого объявления пространства имен в XML.

Выполнение response.doc.css("Body") return blank.

Что можно сделать, чтобы получить значение BodyType?

Поскольку нет никакого смысла в размещении код, который делает запрос на безопасное/личное мыло, я отправляю некоторый базовый код, который читает в 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> 
+0

Когда вы спрашиваете о коде, пожалуйста, уменьшите свой ввод до абсолютного минимума, необходимого для демонстрации проблемы. Все остальное тратит наше время, заставляя нас это делать и потенциально смущает кого-либо другого, ищущего аналогичное решение. Пожалуйста, прочитайте «[mcve]» и [Сколько усилий ожидается от пользователей Stack Overflow?] (Http://meta.stackoverflow.com/a/261593/128421). –

ответ

0

Пространства имен могут действительно мутить воды.

По умолчанию Nokogiri будет искать в корневом узле объявления пространств имен, поэтому t|Body будет работать, если в корневом узле было определено xmlns:t.

Но, поскольку это не так, вы должны использовать 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: