在Ruby中使用来自Nokogiri的Soap调用的XML主体

时间:2016-05-17 20:39:38

标签: ruby xml soap nokogiri

我正在编写一个Ruby脚本来进行Postman SOAP POST调用,然后使用Nokogiri来解析XML响应。当我从Postman获取完整的SOAP调用响应时,将其复制到我的编辑器中并手动获取XML主体并解码并在线格式化我能够成功使用以下Nokogiri脚本:

doc = Nokogiri::XML(File.open("response.xml"))

property_ids = []

doc.css('Property').each do |property|
  puts "Property ID: #{property['PropertyId']}"
  property_ids << property['PropertyId']
end


property_ids.each_with_index do |property_id, index|
  puts "index:  #{index}"
  puts "property id: #{property_id}"
end

当我遇到问题的时候,我想在脚本中包含Postman调用的Ruby片段:

require 'nokogiri'
require 'uri'
require 'net/http'
require 'openssl'


url = URI("https://esite.thelyndco.com/AmsiWeb/eDexWeb/esite/leasing.asmx")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/soap+xml'
request["cache-control"] = 'no-cache'
request["postman-token"] = '916e3f3d-11ca-e8cf-2066-542b009a281d'
request.body = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\">\r\n  <soap12:Body>\r\n    <GetPropertyList xmlns=\"http://tempuri.org/\">\r\n      <UserID>updater</UserID>\r\n      <Password>[password]</Password>\r\n      <PortfolioName>[portfolio name]</PortfolioName>\r\n      <XMLData> \r\n</XMLData>\r\n    </GetPropertyList>\r\n  </soap12:Body>\r\n</soap12:Envelope>"

response = http.request(request)

doc = Nokogiri::XML(response.body)
# doc = Nokogiri::XML(File.open("full-response.xml"))
# doc.at('GetPropertyListResponse').text

我想要做的是使用SOAP信封获取完整的SOAP响应,并且能够在我的脚本中处理它而无需剪切和粘贴;使用在线XML格式化程序手动解码和格式化。

注释掉了我从Stack Overflow尝试过的几行。是否可以使用Nokogiri解码和格式化XML主体或解析SOAP信封?

编辑:

通过解码XML我的意思是:

<GetPropertyListResult>&lt;Properties&gt;&lt;Property PropertyId="11A" PropertyName1="1111 Austin Hwy" PropertyName2="" PropertyAddrLine1="The 1111" PropertyAddrLine2="1111 Austin Highway" PropertyAddrLine3="" PropertyAddrLine4="" PropertyAddrCity="San Antonio" PropertyAddrState="TX" PropertyAddrZipCode="78209" PropertyAddrCountry="" PropertyAddrEmail="" RemitToAddrLine1="The 1111" RemitToAddrLine2="1111 Austin Highway" RemitToAddrLine3="" RemitToAddrLine4="" RemitToAddrCity="San Antonio" RemitToAddrState="TX" RemitToAddrZipCode="78209" RemitToAddrCountry="" LiveDate="2013-12-04T00:00:00" MgrOffPhoneNo="210-804-1100" MgrFaxNo="" MgrSalutation="" MgrFirstName="" MgrMiName="" MgrLastName="" MonthEndInProcess="N"&gt;&lt;Amenity PropertyId="11A" 

并将其解码为使用此online XML decoder

<GetPropertyListResult><Properties><Property PropertyId="11A" PropertyName1="1111 Austin Hwy" PropertyName2="" PropertyAddrLine1="The 1111" PropertyAddrLine2="1111 Austin Highway" PropertyAddrLine3="" PropertyAddrLine4="" PropertyAddrCity="San Antonio" PropertyAddrState="TX" PropertyAddrZipCode="78209" PropertyAddrCountry="" PropertyAddrEmail="" RemitToAddrLine1="The 1111" RemitToAddrLine2="1111 Austin Highway" RemitToAddrLine3="" RemitToAddrLine4="" RemitToAddrCity="San Antonio" RemitToAddrState="TX" RemitToAddrZipCode="78209" RemitToAddrCountry="" LiveDate="2013-12-04T00:00:00" MgrOffPhoneNo="210-804-1100" MgrFaxNo="" MgrSalutation="" MgrFirstName="" MgrMiName="" MgrLastName="" MonthEndInProcess="N"><Amenity PropertyId="11A" 

然后通过XML formatter运行它,以便嵌套元素缩进以便易读。

1 个答案:

答案 0 :(得分:1)

您可以使用此代码解码和格式化XML:

require "nokogiri"

XML_CHAR_ENTITIES = {
  "lt"  => "<",
  "gt"  => ">",
  "amp" => "&",
  "num" => "#",
  "comma" => ","
}

xsl =<<XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="/">
    <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>
XSL


xml = '<GetPropertyListResult>&lt;Properties&gt;&lt;Property PropertyId="11A" PropertyName1="1111 Austin Hwy" PropertyName2="" PropertyAddrLine1="The 1111" PropertyAddrLine2="1111 Austin Highway" PropertyAddrLine3="" PropertyAddrLine4="" PropertyAddrCity="San Antonio" PropertyAddrState="TX" PropertyAddrZipCode="78209" PropertyAddrCountry="" PropertyAddrEmail="" RemitToAddrLine1="The 1111" RemitToAddrLine2="1111 Austin Highway" RemitToAddrLine3="" RemitToAddrLine4="" RemitToAddrCity="San Antonio" RemitToAddrState="TX" RemitToAddrZipCode="78209" RemitToAddrCountry="" LiveDate="2013-12-04T00:00:00" MgrOffPhoneNo="210-804-1100" MgrFaxNo="" MgrSalutation="" MgrFirstName="" MgrMiName="" MgrLastName="" MonthEndInProcess="N"&gt;&lt;Amenity PropertyId="11A"></GetPropertyListResult>'

xml = xml.gsub(/&(\w+);/) do |match|
  char_entity = XML_CHAR_ENTITIES[$1]
  char_entity ? char_entity : match
end

doc  = Nokogiri::XML(xml)
xslt = Nokogiri::XSLT(xsl)
xml  = xslt.transform(doc)

puts "#{xml}"

提供的XML不完整,因此附加了此终止字符串以允许对其进行解析:></GetPropertyListResult>

XML_CHAR_ENTITIES为已解码的字符串提供编码字符串的哈希值,并且可以轻松扩展为包含其他XML字符实体,例如W3 Character Entity Reference Chart中记录的那些。

XSL是一个嵌入式样式表,用于使用Nokogiri格式化输出XML。

使用块选项通过String#gsub调用解码XML字符实体。然后,Nokogiri成功解析了XML。解析XML后,使用Nokogiri XSLT转换对其进行格式化。

此代码的输出为:

<?xml version="1.0" encoding="UTF-8"?>
<GetPropertyListResult>
  <Properties>
    <Property PropertyId="11A" PropertyName1="1111 Austin Hwy" PropertyName2="" PropertyAddrLine1="The 1111" PropertyAddrLine2="1111 Austin Highway" PropertyAddrLine3="" PropertyAddrLine4="" PropertyAddrCity="San Antonio" PropertyAddrState="TX" PropertyAddrZipCode="78209" PropertyAddrCountry="" PropertyAddrEmail="" RemitToAddrLine1="The 1111" RemitToAddrLine2="1111 Austin Highway" RemitToAddrLine3="" RemitToAddrLine4="" RemitToAddrCity="San Antonio" RemitToAddrState="TX" RemitToAddrZipCode="78209" RemitToAddrCountry="" LiveDate="2013-12-04T00:00:00" MgrOffPhoneNo="210-804-1100" MgrFaxNo="" MgrSalutation="" MgrFirstName="" MgrMiName="" MgrLastName="" MonthEndInProcess="N">
      <Amenity PropertyId="11A"/>
    </Property>
  </Properties>
</GetPropertyListResult>