source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/soap/generator.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 6.7 KB
Line 
1# SOAP4R - SOAP XML Instance Generator library.
2# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi <[email protected]>.
3
4# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5# redistribute it and/or modify it under the same terms of Ruby's license;
6# either the dual license version in 2003, or any later version.
7
8
9require 'xsd/ns'
10require 'soap/soap'
11require 'soap/baseData'
12require 'soap/encodingstyle/handler'
13
14
15module SOAP
16
17
18###
19## CAUTION: MT-unsafe
20#
21class SOAPGenerator
22 include SOAP
23
24 class FormatEncodeError < Error; end
25
26public
27
28 attr_accessor :charset
29 attr_accessor :default_encodingstyle
30 attr_accessor :generate_explicit_type
31 attr_accessor :use_numeric_character_reference
32
33 def initialize(opt = {})
34 @reftarget = nil
35 @handlers = {}
36 @charset = opt[:charset] || XSD::Charset.xml_encoding_label
37 @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
38 @generate_explicit_type =
39 opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true
40 @elementformdefault = opt[:elementformdefault]
41 @attributeformdefault = opt[:attributeformdefault]
42 @use_numeric_character_reference = opt[:use_numeric_character_reference]
43 @indentstr = opt[:no_indent] ? '' : ' '
44 @buf = @indent = @curr = nil
45 end
46
47 def generate(obj, io = nil)
48 @buf = io || ''
49 @indent = ''
50
51 prologue
52 @handlers.each do |uri, handler|
53 handler.encode_prologue
54 end
55
56 ns = XSD::NS.new
57 @buf << xmldecl
58 encode_data(ns, obj, nil)
59
60 @handlers.each do |uri, handler|
61 handler.encode_epilogue
62 end
63 epilogue
64
65 @buf
66 end
67
68 def encode_data(ns, obj, parent)
69 if obj.is_a?(SOAPEnvelopeElement)
70 encode_element(ns, obj, parent)
71 return
72 end
73 if @reftarget && !obj.precedents.empty?
74 add_reftarget(obj.elename.name, obj)
75 ref = SOAPReference.new(obj)
76 ref.elename = ref.elename.dup_name(obj.elename.name)
77 obj.precedents.clear # Avoid cyclic delay.
78 obj.encodingstyle = parent.encodingstyle
79 # SOAPReference is encoded here.
80 obj = ref
81 end
82 encodingstyle = obj.encodingstyle
83 # Children's encodingstyle is derived from its parent.
84 encodingstyle ||= parent.encodingstyle if parent
85 obj.encodingstyle = encodingstyle
86 handler = find_handler(encodingstyle || @default_encodingstyle)
87 unless handler
88 raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
89 end
90 if !obj.elename.name
91 raise FormatEncodeError.new("Element name not defined: #{ obj }.")
92 end
93 handler.encode_data(self, ns, obj, parent)
94 handler.encode_data_end(self, ns, obj, parent)
95 end
96
97 def add_reftarget(name, node)
98 unless @reftarget
99 raise FormatEncodeError.new("Reftarget is not defined.")
100 end
101 @reftarget.add(name, node)
102 end
103
104 def encode_child(ns, child, parent)
105 indent_backup, @indent = @indent, @indent + @indentstr
106 encode_data(ns.clone_ns, child, parent)
107 @indent = indent_backup
108 end
109
110 def encode_element(ns, obj, parent)
111 attrs = {}
112 if obj.is_a?(SOAPBody)
113 @reftarget = obj
114 obj.encode(self, ns, attrs) do |child|
115 indent_backup, @indent = @indent, @indent + @indentstr
116 encode_data(ns.clone_ns, child, obj)
117 @indent = indent_backup
118 end
119 @reftarget = nil
120 else
121 if obj.is_a?(SOAPEnvelope)
122 # xsi:nil="true" can appear even if dumping without explicit type.
123 SOAPGenerator.assign_ns(attrs, ns,
124 XSD::InstanceNamespace, XSINamespaceTag)
125 if @generate_explicit_type
126 SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag)
127 end
128 end
129 obj.encode(self, ns, attrs) do |child|
130 indent_backup, @indent = @indent, @indent + @indentstr
131 encode_data(ns.clone_ns, child, obj)
132 @indent = indent_backup
133 end
134 end
135 end
136
137 def encode_name(ns, data, attrs)
138 if element_local?(data)
139 data.elename.name
140 else
141 if element_qualified?(data)
142 SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '')
143 else
144 SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
145 end
146 ns.name(data.elename)
147 end
148 end
149
150 def encode_name_end(ns, data)
151 if element_local?(data)
152 data.elename.name
153 else
154 ns.name(data.elename)
155 end
156 end
157
158 def encode_tag(elename, attrs = nil)
159 if !attrs or attrs.empty?
160 @buf << "\n#{ @indent }<#{ elename }>"
161 elsif attrs.size == 1
162 key, value = attrs.shift
163 @buf << %Q[\n#{ @indent }<#{ elename } #{ key }="#{ value }">]
164 else
165 @buf << "\n#{ @indent }<#{ elename } " <<
166 attrs.collect { |key, value|
167 %Q[#{ key }="#{ value }"]
168 }.join("\n#{ @indent }#{ @indentstr * 2 }") <<
169 '>'
170 end
171 end
172
173 def encode_tag_end(elename, cr = nil)
174 if cr
175 @buf << "\n#{ @indent }</#{ elename }>"
176 else
177 @buf << "</#{ elename }>"
178 end
179 end
180
181 def encode_rawstring(str)
182 @buf << str
183 end
184
185 EncodeMap = {
186 '&' => '&amp;',
187 '<' => '&lt;',
188 '>' => '&gt;',
189 '"' => '&quot;',
190 '\'' => '&apos;',
191 "\r" => '&#xd;'
192 }
193 EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]")
194 def encode_string(str)
195 if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str)
196 str.gsub!(EncodeCharRegexp) { |c| EncodeMap[c] }
197 @buf << str.unpack("U*").collect { |c|
198 if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f)
199 c.chr
200 else
201 sprintf("&#x%x;", c)
202 end
203 }.join
204 else
205 @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] }
206 end
207 end
208
209 def element_local?(element)
210 element.elename.namespace.nil?
211 end
212
213 def element_qualified?(element)
214 if element.respond_to?(:qualified)
215 if element.qualified.nil?
216 @elementformdefault
217 else
218 element.qualified
219 end
220 else
221 @elementformdefault
222 end
223 end
224
225 def self.assign_ns(attrs, ns, namespace, tag = nil)
226 if namespace.nil?
227 raise FormatEncodeError.new("empty namespace")
228 end
229 unless ns.assigned?(namespace)
230 tag = ns.assign(namespace, tag)
231 if tag == ''
232 attr = 'xmlns'
233 else
234 attr = "xmlns:#{tag}"
235 end
236 attrs[attr] = namespace
237 end
238 end
239
240private
241
242 def prologue
243 end
244
245 def epilogue
246 end
247
248 def find_handler(encodingstyle)
249 unless @handlers.key?(encodingstyle)
250 handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset)
251 handler.generate_explicit_type = @generate_explicit_type
252 handler.encode_prologue
253 @handlers[encodingstyle] = handler
254 end
255 @handlers[encodingstyle]
256 end
257
258 def xmldecl
259 if @charset
260 %Q[<?xml version="1.0" encoding="#{ @charset }" ?>]
261 else
262 %Q[<?xml version="1.0" ?>]
263 end
264 end
265end
266
267
268end
Note: See TracBrowser for help on using the repository browser.