【问题标题】:Working with XML body from Soap call with Nokogiri in Ruby在 Ruby 中使用 Nokogiri 处理来自 Soap 调用的 XML 主体
【发布时间】:2016-05-17 20:39:37
【问题描述】:

我正在编写一个 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 sn-p 时:

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 运行它,以便嵌套元素缩进以便于阅读。

【问题讨论】:

  • 在这种情况下动词“解码”和“格式”是什么意思?您实际上需要使用 Ruby 代码完成哪些手动操作?
  • @MichaelGaskill,为澄清 xml 解码和格式化而编辑的问题。

标签: ruby xml soap nokogiri


【解决方案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 不完整,因此附加了这个终止字符串以允许对其进行解析:&gt;&lt;/GetPropertyListResult&gt;

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-12
    相关资源
    最近更新 更多