在 Ruby 中使用 Nokogiri Soap 调用中的 XML 正文

Working with XML body from Soap call with Nokogiri in Ruby

我正在编写一个 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 对其进行调整,以便嵌套元素缩进以便于阅读。

您可以使用此代码解码和格式化 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[]
  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 中记录的那些。 =15=]

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

解码 XML 字符实体是通过使用块选项的 String#gsub 调用完成的。然后 XML 被 Nokogiri 成功解析。解析 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>