From db9445103c082a306ba085f7677da02ea94b8841 Mon Sep 17 00:00:00 2001 From: nahi Date: Wed, 24 Sep 2003 15:18:44 +0000 Subject: * lib/soap/* (29 files): SOAP4R added. * lib/wsdl/* (42 files): WSDL4R added. * lib/xsd/* (12 files): XSD4R added. * test/soap/* (16 files): added. * test/wsdl/* (2 files): added. * test/xsd/* (3 files): added. * sample/soap/* (27 files): added. * sample/wsdl/* (13 files): added. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4591 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/soap/generator.rb | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 lib/soap/generator.rb (limited to 'lib/soap/generator.rb') diff --git a/lib/soap/generator.rb b/lib/soap/generator.rb new file mode 100644 index 0000000000..6707aef195 --- /dev/null +++ b/lib/soap/generator.rb @@ -0,0 +1,206 @@ +=begin +SOAP4R - SOAP XML Instance Generator library. +Copyright (C) 2001, 2003 NAKAMURA, Hiroshi. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PRATICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 675 Mass +Ave, Cambridge, MA 02139, USA. +=end + + +require 'xsd/ns' +require 'soap/soap' +require 'soap/baseData' +require 'soap/encodingstyle/handler' + + +module SOAP + + +### +## CAUTION: MT-unsafe +# +class SOAPGenerator + include SOAP + + class FormatEncodeError < Error; end + +public + + attr_accessor :charset + attr_accessor :default_encodingstyle + attr_accessor :generate_explicit_type + attr_accessor :pretty + + def initialize(opt = {}) + @reftarget = nil + @handlers = {} + @charset = opt[:charset] || XSD::Charset.encoding_label + @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace + @generate_explicit_type = + opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true + @pretty = true # opt[:pretty] + end + + def generate(obj, io = nil) + prologue + @handlers.each do |uri, handler| + handler.encode_prologue + end + + io = '' if io.nil? + + ns = XSD::NS.new + io << xmldecl + encode_data(io, ns, true, obj, nil, 0) + + @handlers.each do |uri, handler| + handler.encode_epilogue + end + epilogue + + io + end + + def encode_data(buf, ns, qualified, obj, parent, indent) + if obj.is_a?(SOAPEnvelopeElement) + encode_element(buf, ns, qualified, obj, parent, indent) + return + end + + if @reftarget && !obj.precedents.empty? + @reftarget.add(obj.elename.name, obj) + ref = SOAPReference.new + ref.elename.name = obj.elename.name + ref.__setobj__(obj) + obj.precedents.clear # Avoid cyclic delay. + obj.encodingstyle = parent.encodingstyle + # SOAPReference is encoded here. + obj = ref + end + + encodingstyle = obj.encodingstyle + # Children's encodingstyle is derived from its parent. + encodingstyle ||= parent.encodingstyle if parent + obj.encodingstyle = encodingstyle + + handler = find_handler(encodingstyle || @default_encodingstyle) + unless handler + raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.") + end + + if !obj.elename.name + raise FormatEncodeError.new("Element name not defined: #{ obj }.") + end + + indent_str = ' ' * indent + child_indent = @pretty ? indent + 2 : indent + handler.encode_data(buf, ns, qualified, obj, parent, indent_str) do |child, child_q| + encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent) + end + handler.encode_data_end(buf, ns, qualified, obj, parent, indent_str) + end + + def encode_element(buf, ns, qualified, obj, parent, indent) + indent_str = ' ' * indent + child_indent = @pretty ? indent + 2 : indent + attrs = {} + if obj.is_a?(SOAPBody) + @reftarget = obj + obj.encode(buf, ns, attrs, indent_str) do |child, child_q| + encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent) + end + @reftarget = nil + else + if obj.is_a?(SOAPEnvelope) + # xsi:nil="true" can appear even if dumping without explicit type. + SOAPGenerator.assign_ns(attrs, ns, + XSD::InstanceNamespace, XSINamespaceTag) + if @generate_explicit_type + SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag) + end + end + obj.encode(buf, ns, attrs, indent_str) do |child, child_q| + encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent) + end + end + end + + def self.assign_ns(attrs, ns, namespace, tag = nil) + unless ns.assigned?(namespace) + tag = ns.assign(namespace, tag) + attrs['xmlns:' << tag] = namespace + end + end + + def self.encode_tag(buf, elename, attrs = nil, indent = '') + if attrs + buf << "\n#{ indent }<#{ elename }" << + attrs.collect { |key, value| + %Q[ #{ key }="#{ value }"] + }.join << + '>' + else + buf << "\n#{ indent }<#{ elename }>" + end + end + + def self.encode_tag_end(buf, elename, indent = '', cr = nil) + if cr + buf << "\n#{ indent }" + else + buf << "" + end + end + + EncodeMap = { + '&' => '&', + '<' => '<', + '>' => '>', + '"' => '"', + '\'' => ''', + "\r" => ' ' + } + EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]") + def self.encode_str(str) + str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } + end + +private + + def prologue + end + + def epilogue + end + + def find_handler(encodingstyle) + unless @handlers.key?(encodingstyle) + handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset) + handler.generate_explicit_type = @generate_explicit_type + handler.encode_prologue + @handlers[encodingstyle] = handler + end + @handlers[encodingstyle] + end + + def xmldecl + if @charset + %Q[] + else + %Q[] + end + end +end + + +end -- cgit v1.2.3