Skip to content

Instantly share code, notes, and snippets.

@matthewd
Last active October 24, 2015 01:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewd/278b2294486c1d38f8f6 to your computer and use it in GitHub Desktop.
Save matthewd/278b2294486c1d38f8f6 to your computer and use it in GitHub Desktop.
diff --git a/gems/pending/VMwareWebService/VimService.rb b/gems/pending/VMwareWebService/VimService.rb
index 0f204d5..60c2992 100644
--- a/gems/pending/VMwareWebService/VimService.rb
+++ b/gems/pending/VMwareWebService/VimService.rb
@@ -1,5 +1,19 @@
require "handsoap"
require 'VMwareWebService/VimTypes'
+require 'active_support/core_ext/object/blank'
+
+class Handsoap::Service::Response < Struct.new(:content, :namespace)
+ def self.new(content, namespace)
+ if content =~ /<soapenv:Fault>/
+ Handsoap::Response.new(content, namespace)
+ else
+ super
+ end
+ end
+
+ def fault?
+ end
+end
class VimService < Handsoap::Service
attr_reader :sic, :about, :apiVersion, :isVirtualCenter, :v20, :v2, :v4, :serviceInstanceMor
@@ -1170,67 +1184,113 @@ def marshalObj(node, obj)
end
end
- def parse_response(response, rType)
- doc = response.document
- raise "Response <#{response.inspect}> has no XML document" if doc.nil?
- search_path = "//n1:#{rType}"
- node = doc.xpath(search_path, @ns).first
- raise "Node (search=<#{search_path}> namespace=<#{@ns}>) not found in XML document <#{doc.inspect}>" if node.nil?
- ur = unmarshal_response(node, rType)
- # puts
- # puts "***** #{rType}"
- # dumpObj(ur)
- # puts
- (ur)
+ class Parser < Nokogiri::XML::SAX::Document
+ def initialize(target)
+ @target = target
+ @base_type = target
+
+ @contents = [[]]
+ @elements = []
+
+ @string = nil
+ end
+
+ ARRAY_MAP = Hash.new { |h, k| h[k] = k =~ /^ArrayOf(.*)$/ && $1.to_sym }
+ MAPPER_MAP = Hash.new { |h, k| h[k] = -> _ { {:type => k} } }
+
+ def content
+ @contents.first.last.last
+ end
+
+ def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
+ return if @target && name != @target
+ @target = nil
+
+ raise "Mixed content not supported" if @string
+
+ name = name.freeze
+
+ vimType = xsiType = nil
+ attrs.each do |att|
+ if att.uri
+ xsiType = att.value
+ else
+ vimType = att.value
+ end
+ end
+ xsiType ||= if @elements.last
+ ai = @elements.last && @elements.last[3]
+ if (aih = ai && ai[name])
+ aih[:type]
+ else
+ ''.freeze
+ end
+ else
+ @base_type
+ end
+
+ if (s = ARRAY_MAP[xsiType])
+ aih = MAPPER_MAP[s]
+ else
+ aih = VimMappingRegistry.argInfoMap(xsiType)
+ end
+
+ @elements << [name, vimType, xsiType, aih]
+ @contents << []
+ end
+
+ def characters(string)
+ return if @target
+ return if string.blank?
+
+ if @string
+ @string << string
+ else
+ @string = string
+ end
+ end
+ alias_method :cdata_block, :characters
+
+ def end_element_namespace(name, prefix = nil, uri = nil)
+ return if @elements.empty?
+ entry = @elements.pop
+ name = entry.first
+ aih = entry.pop
+ xsiType = entry.pop
+ vimType = entry.pop
+
+ value = nil
+ contents = @contents.pop
+
+ if @string
+ value = VimString.new(@string, vimType, xsiType)
+ @string = nil
+ elsif xsiType == "SOAP::SOAPString".freeze || xsiType == :"SOAP::SOAPString"
+ value = VimString.new(''.freeze, vimType, xsiType)
+ elsif ARRAY_MAP[xsiType]
+ value = VimArray.new(xsiType)
+ contents.each do |_cname, cvalue|
+ value << cvalue
+ end
+ else
+ value = VimHash.new(xsiType)
+ contents.each do |cname, cvalue|
+ if aih && (z = aih[cname]) && z[:isArray]
+ (value[cname] ||= VimArray.new(:"ArrayOf#{z[:type]}")) << cvalue
+ else
+ value[cname] = cvalue
+ end
+ end
+ end
+
+ @contents.last << (entry << value)
+ end
end
- def unmarshal_response(node, vType = nil)
- return(node.text) if node.text?
-
- vimType = node.attribute_with_ns('type'.freeze, nil)
- vimType = vimType.value if vimType
- xsiType = node.attribute_with_ns('type'.freeze, 'http://www.w3.org/2001/XMLSchema-instance'.freeze)
- xsiType = xsiType.value if xsiType
- xsiType ||= vType ? vType.to_s : ''.freeze
-
- if (c = node.child) && c.text? && !c.next_sibling
- return VimString.new(c.text, vimType, xsiType)
- end
- if xsiType == "SOAP::SOAPString".freeze
- return VimString.new("".freeze, vimType, xsiType)
- end
-
- if xsiType =~ /^ArrayOf(.*)$/
- nextType = $1
- obj = VimArray.new(xsiType)
- node.children.each do |c|
- next if c.blank?
- obj << unmarshal_response(c, nextType)
- end
- return(obj)
- end
-
- aih = VimMappingRegistry.argInfoMap(xsiType)
- obj = VimHash.new(xsiType)
-
- node.children.each do |c|
- next if c.blank?
- name = c.name.freeze
-
- ai = aih[name] if aih
-
- unless (v = obj[name])
- v = obj[name] = VimArray.new("ArrayOf#{ai[:type]}") if ai && ai[:isArray]
- end
-
- nextType = (ai ? ai[:type] : nil)
-
- if v.kind_of?(Array)
- obj[name] << unmarshal_response(c, nextType)
- else
- obj[name] = unmarshal_response(c, nextType)
- end
- end
- (obj)
+ def parse_response(response, rType)
+ xml = response.content
+ px = Parser.new(rType)
+ Nokogiri::XML::SAX::Parser.new(px).parse(xml)
+ px.content
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment