handsoap 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +105 -0
- data/VERSION.yml +4 -0
- data/generators/handsoap/USAGE +0 -0
- data/generators/handsoap/handsoap_generator.rb +113 -0
- data/generators/handsoap/templates/DUMMY +0 -0
- data/lib/handsoap.rb +4 -0
- data/lib/handsoap/compiler.rb +182 -0
- data/lib/handsoap/deferred.rb +50 -0
- data/lib/handsoap/http.rb +4 -0
- data/lib/handsoap/http/drivers.rb +24 -0
- data/lib/handsoap/http/drivers/abstract_driver.rb +170 -0
- data/lib/handsoap/http/drivers/curb_driver.rb +41 -0
- data/lib/handsoap/http/drivers/event_machine_driver.rb +46 -0
- data/lib/handsoap/http/drivers/http_client_driver.rb +38 -0
- data/lib/handsoap/http/drivers/mock_driver.rb +39 -0
- data/lib/handsoap/http/drivers/net_http_driver.rb +69 -0
- data/lib/handsoap/http/part.rb +78 -0
- data/lib/handsoap/http/request.rb +63 -0
- data/lib/handsoap/http/response.rb +28 -0
- data/lib/handsoap/parser.rb +241 -0
- data/lib/handsoap/service.rb +481 -0
- data/lib/handsoap/xml_mason.rb +221 -0
- data/lib/handsoap/xml_query_front.rb +320 -0
- metadata +81 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Handsoap
|
4
|
+
|
5
|
+
# XmlMason is a simple XML builder.
|
6
|
+
module XmlMason
|
7
|
+
|
8
|
+
XML_ESCAPE = { '&' => '&', '"' => '"', '>' => '>', '<' => '<' }
|
9
|
+
|
10
|
+
def self.xml_escape(s)
|
11
|
+
s.to_s.gsub(/[&"><]/) { |special| XML_ESCAPE[special] }
|
12
|
+
end
|
13
|
+
|
14
|
+
class Node
|
15
|
+
def initialize
|
16
|
+
@namespaces = {}
|
17
|
+
end
|
18
|
+
def add(node_name, value = nil, *flags) # :yields: Handsoap::XmlMason::Element
|
19
|
+
prefix, name = parse_ns(node_name)
|
20
|
+
node = append_child Element.new(self, prefix, name, value, flags)
|
21
|
+
if block_given?
|
22
|
+
yield node
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# Registers a prefix for a namespace.
|
26
|
+
#
|
27
|
+
# You must register a namespace, before you can refer it.
|
28
|
+
def alias(prefix, namespaces)
|
29
|
+
@namespaces[prefix] = namespaces
|
30
|
+
end
|
31
|
+
# Finds the first element whos +node_name+ equals +name+
|
32
|
+
#
|
33
|
+
# Doesn't regard namespaces/prefixes.
|
34
|
+
def find(name)
|
35
|
+
raise NotImplementedError.new
|
36
|
+
end
|
37
|
+
# Finds all elements whos +node_name+ equals +name+
|
38
|
+
#
|
39
|
+
# Doesn't regard namespaces/prefixes.
|
40
|
+
def find_all(name)
|
41
|
+
raise NotImplementedError.new
|
42
|
+
end
|
43
|
+
def parse_ns(name)
|
44
|
+
matches = name.match /^([^:]+):(.*)$/
|
45
|
+
if matches
|
46
|
+
[matches[1] == '*' ? @prefix : matches[1], matches[2]]
|
47
|
+
else
|
48
|
+
[nil, name]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
private :parse_ns
|
52
|
+
end
|
53
|
+
|
54
|
+
class Document < Node
|
55
|
+
def initialize # :yields: Document
|
56
|
+
super
|
57
|
+
@document_element = nil
|
58
|
+
@xml_header = true
|
59
|
+
if block_given?
|
60
|
+
yield self
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def xml_header=(xml_header)
|
64
|
+
@xml_header = !! xml_header
|
65
|
+
end
|
66
|
+
def append_child(node)
|
67
|
+
if not @document_element.nil?
|
68
|
+
raise "There can only be one element at the top level."
|
69
|
+
end
|
70
|
+
@document_element = node
|
71
|
+
end
|
72
|
+
def find(name)
|
73
|
+
@document_element.find(name)
|
74
|
+
end
|
75
|
+
def find_all(name)
|
76
|
+
@document_element.find_all(name)
|
77
|
+
end
|
78
|
+
def get_namespace(prefix)
|
79
|
+
@namespaces[prefix] || raise("No alias registered for prefix '#{prefix}'")
|
80
|
+
end
|
81
|
+
def defines_namespace?(prefix)
|
82
|
+
false
|
83
|
+
end
|
84
|
+
def to_s
|
85
|
+
if @document_element.nil?
|
86
|
+
raise "No document element added."
|
87
|
+
end
|
88
|
+
(@xml_header ? "<?xml version='1.0' ?>\n" : "") + @document_element.to_s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class TextNode
|
93
|
+
def initialize(text)
|
94
|
+
@text = text
|
95
|
+
end
|
96
|
+
def to_s(indentation = '')
|
97
|
+
XmlMason.xml_escape(@text)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class RawContent < TextNode
|
102
|
+
def to_s(indentation = '')
|
103
|
+
@text
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Element < Node
|
108
|
+
def initialize(parent, prefix, node_name, value = nil, flags = []) # :yields: Handsoap::XmlMason::Element
|
109
|
+
super()
|
110
|
+
# if prefix.to_s == ""
|
111
|
+
# raise "missing prefix"
|
112
|
+
# end
|
113
|
+
@parent = parent
|
114
|
+
@prefix = prefix
|
115
|
+
@node_name = node_name
|
116
|
+
@children = []
|
117
|
+
@attributes = {}
|
118
|
+
if not value.nil?
|
119
|
+
set_value value.to_s, *flags
|
120
|
+
end
|
121
|
+
if block_given?
|
122
|
+
yield self
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# Returns the document that this element belongs to, or self if this is the document.
|
126
|
+
def document
|
127
|
+
@parent.respond_to?(:document) ? @parent.document : @parent
|
128
|
+
end
|
129
|
+
# Returns the qname (prefix:nodename)
|
130
|
+
def full_name
|
131
|
+
@prefix.nil? ? @node_name : (@prefix + ":" + @node_name)
|
132
|
+
end
|
133
|
+
# Adds a child node.
|
134
|
+
#
|
135
|
+
# You usually won't need to call this method, but will rather use +add+
|
136
|
+
def append_child(node)
|
137
|
+
if value_node?
|
138
|
+
raise "Element already has a text value. Can't add nodes"
|
139
|
+
end
|
140
|
+
@children << node
|
141
|
+
return node
|
142
|
+
end
|
143
|
+
# Sets the inner text of this element.
|
144
|
+
#
|
145
|
+
# By default the string is escaped, but you can pass the flag :raw to inject XML.
|
146
|
+
#
|
147
|
+
# You usually won't need to call this method, but will rather use +add+
|
148
|
+
def set_value(value, *flags)
|
149
|
+
if @children.length > 0
|
150
|
+
raise "Element already has children. Can't set value"
|
151
|
+
end
|
152
|
+
if flags && flags.include?(:raw)
|
153
|
+
@children = [RawContent.new(value)]
|
154
|
+
else
|
155
|
+
@children = [TextNode.new(value)]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
# Sets the value of an attribute.
|
159
|
+
def set_attr(name, value)
|
160
|
+
full_name = parse_ns(name).join(":")
|
161
|
+
@attributes[name] = value
|
162
|
+
end
|
163
|
+
def find(name)
|
164
|
+
name = name.to_s if name.kind_of? Symbol
|
165
|
+
if @node_name == name || full_name == name
|
166
|
+
return self
|
167
|
+
end
|
168
|
+
@children.each do |node|
|
169
|
+
if node.respond_to? :find
|
170
|
+
tmp = node.find(name)
|
171
|
+
if tmp
|
172
|
+
return tmp
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
def find_all(name)
|
179
|
+
name = name.to_s if name.kind_of? Symbol
|
180
|
+
result = []
|
181
|
+
if @node_name == name || full_name == name
|
182
|
+
result << self
|
183
|
+
end
|
184
|
+
@children.each do |node|
|
185
|
+
if node.respond_to? :find
|
186
|
+
result = result.concat(node.find_all(name))
|
187
|
+
end
|
188
|
+
end
|
189
|
+
return result
|
190
|
+
end
|
191
|
+
def value_node?
|
192
|
+
@children.length == 1 && @children[0].kind_of?(TextNode)
|
193
|
+
end
|
194
|
+
def get_namespace(prefix)
|
195
|
+
@namespaces[prefix] || @parent.get_namespace(prefix)
|
196
|
+
end
|
197
|
+
def defines_namespace?(prefix)
|
198
|
+
@attributes.keys.include?("xmlns:#{prefix}") || @parent.defines_namespace?(prefix)
|
199
|
+
end
|
200
|
+
def to_s(indentation = '')
|
201
|
+
# todo resolve attribute prefixes aswell
|
202
|
+
if @prefix && (not defines_namespace?(@prefix))
|
203
|
+
set_attr "xmlns:#{@prefix}", get_namespace(@prefix)
|
204
|
+
end
|
205
|
+
name = XmlMason.xml_escape(full_name)
|
206
|
+
attr = (@attributes.any? ? (" " + @attributes.map { |key, value| XmlMason.xml_escape(key) + '="' + XmlMason.xml_escape(value) + '"' }.join(" ")) : "")
|
207
|
+
if @children.any?
|
208
|
+
if value_node?
|
209
|
+
children = @children[0].to_s(indentation + " ")
|
210
|
+
else
|
211
|
+
children = @children.map { |node| "\n" + node.to_s(indentation + " ") }.join("") + "\n" + indentation
|
212
|
+
end
|
213
|
+
indentation + "<" + name + attr + ">" + children + "</" + name + ">"
|
214
|
+
else
|
215
|
+
indentation + "<" + name + attr + " />"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
@@ -0,0 +1,320 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Handsoap
|
3
|
+
#
|
4
|
+
# A simple frontend for parsing XML document with Xpath.
|
5
|
+
#
|
6
|
+
# This provides a unified interface for multiple xpath-capable dom-parsers,
|
7
|
+
# allowing seamless switching between the underlying implementations.
|
8
|
+
#
|
9
|
+
# A document is loaded using the function Handsoap::XmlQueryFront.parse_string, passing
|
10
|
+
# the xml source string and a driver, which can (currently) be one of:
|
11
|
+
#
|
12
|
+
# :rexml
|
13
|
+
# :nokogiri
|
14
|
+
# :libxml
|
15
|
+
#
|
16
|
+
# The resulting object is a wrapper, of the type Handsoap::XmlQueryFront::XmlElement.
|
17
|
+
#
|
18
|
+
module XmlQueryFront
|
19
|
+
|
20
|
+
# This error is raised if the document didn't parse
|
21
|
+
class ParseError < RuntimeError; end
|
22
|
+
|
23
|
+
# Loads requirements for a driver.
|
24
|
+
#
|
25
|
+
# This function is implicitly called by +parse_string+.
|
26
|
+
def self.load_driver!(driver)
|
27
|
+
if driver == :rexml
|
28
|
+
require 'rexml/document'
|
29
|
+
elsif driver == :nokogiri
|
30
|
+
require 'nokogiri'
|
31
|
+
begin
|
32
|
+
gem('nokogiri') # work around bug in rubygems for Ruby 1.9
|
33
|
+
|
34
|
+
if Gem.loaded_specs['nokogiri'].version < Gem::Version.new('1.3.0')
|
35
|
+
raise "Incompatible version of Nokogiri. Please upgrade gem."
|
36
|
+
end
|
37
|
+
rescue NoMethodError
|
38
|
+
end
|
39
|
+
elsif driver == :libxml
|
40
|
+
require 'libxml'
|
41
|
+
else
|
42
|
+
raise "Unknown driver #{driver}"
|
43
|
+
end
|
44
|
+
return driver
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a wrapped XML parser, using the requested driver.
|
48
|
+
#
|
49
|
+
# +driver+ can be one of the following:
|
50
|
+
# :rexml
|
51
|
+
# :nokogiri
|
52
|
+
# :libxml
|
53
|
+
def self.parse_string(xml_string, driver)
|
54
|
+
load_driver!(driver)
|
55
|
+
if driver == :rexml
|
56
|
+
doc = REXML::Document.new(xml_string)
|
57
|
+
raise ParseError.new if doc.root.nil?
|
58
|
+
XmlQueryFront::REXMLDriver.new(doc)
|
59
|
+
elsif driver == :nokogiri
|
60
|
+
doc = Nokogiri::XML(xml_string)
|
61
|
+
raise ParseError.new unless (doc && doc.root && doc.errors.empty?)
|
62
|
+
XmlQueryFront::NokogiriDriver.new(doc)
|
63
|
+
elsif driver == :libxml
|
64
|
+
begin
|
65
|
+
LibXML::XML::Error.set_handler &LibXML::XML::Error::QUIET_HANDLER
|
66
|
+
doc = XmlQueryFront::LibXMLDriver.new(LibXML::XML::Parser.string(xml_string).parse)
|
67
|
+
rescue ArgumentError, LibXML::XML::Error => ex
|
68
|
+
raise ParseError.new
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# NodeSelection is a wrapper around Array, that implicitly delegates XmlElement methods to the first element.
|
74
|
+
#
|
75
|
+
# It makes mapping code prettier, since you often need to access the first element of a selection.
|
76
|
+
class NodeSelection < Array
|
77
|
+
def to_i
|
78
|
+
self.first.to_i if self.any?
|
79
|
+
end
|
80
|
+
def to_f
|
81
|
+
self.first.to_f if self.any?
|
82
|
+
end
|
83
|
+
def to_boolean
|
84
|
+
self.first.to_boolean if self.any?
|
85
|
+
end
|
86
|
+
def to_date
|
87
|
+
self.first.to_date if self.any?
|
88
|
+
end
|
89
|
+
def to_s
|
90
|
+
self.first.to_s if self.any?
|
91
|
+
end
|
92
|
+
def node_name
|
93
|
+
self.first.node_name if self.any?
|
94
|
+
end
|
95
|
+
def xpath(expression, ns = nil)
|
96
|
+
self.first.xpath(expression, ns)
|
97
|
+
end
|
98
|
+
def /(expression)
|
99
|
+
self.first.xpath(expression)
|
100
|
+
end
|
101
|
+
def to_xml
|
102
|
+
self.first.to_xml if self.any?
|
103
|
+
end
|
104
|
+
def to_raw
|
105
|
+
self.first.to_raw if self.any?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Wraps the underlying (native) xml driver, and provides a uniform interface.
|
110
|
+
module XmlElement
|
111
|
+
def initialize(element, namespaces = {})
|
112
|
+
@element = element
|
113
|
+
@namespaces = namespaces
|
114
|
+
end
|
115
|
+
# Registers a prefix to refer to a namespace.
|
116
|
+
#
|
117
|
+
# You can either register a nemspace with this function or pass it explicitly to the +xpath+ method.
|
118
|
+
def add_namespace(prefix, uri)
|
119
|
+
@namespaces[prefix] = uri
|
120
|
+
end
|
121
|
+
# Checks that an xpath-query doesn't refer to any undefined prefixes in +ns+
|
122
|
+
def assert_prefixes!(expression, ns)
|
123
|
+
expression.scan(/([a-zA-Z_][a-zA-Z0-9_.-]*):[^:]+/).map{|m| m[0] }.each do |prefix|
|
124
|
+
raise "Undefined prefix '#{prefix}' in #{ns.inspect}" if ns[prefix].nil?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
# Returns the value of the element as an integer.
|
128
|
+
#
|
129
|
+
# See +to_s+
|
130
|
+
def to_i
|
131
|
+
t = self.to_s
|
132
|
+
return if t.nil?
|
133
|
+
t.to_i
|
134
|
+
end
|
135
|
+
# Returns the value of the element as a float.
|
136
|
+
#
|
137
|
+
# See +to_s+
|
138
|
+
def to_f
|
139
|
+
t = self.to_s
|
140
|
+
return if t.nil?
|
141
|
+
t.to_f
|
142
|
+
end
|
143
|
+
# Returns the value of the element as an boolean.
|
144
|
+
#
|
145
|
+
# See +to_s+
|
146
|
+
def to_boolean
|
147
|
+
t = self.to_s
|
148
|
+
return if t.nil?
|
149
|
+
t.downcase == 'true'
|
150
|
+
end
|
151
|
+
# Returns the value of the element as a ruby Time object.
|
152
|
+
#
|
153
|
+
# See +to_s+
|
154
|
+
def to_date
|
155
|
+
t = self.to_s
|
156
|
+
return if t.nil?
|
157
|
+
Time.iso8601(t)
|
158
|
+
end
|
159
|
+
# Returns the inner text content of this element, or the value (if it's an attr or textnode).
|
160
|
+
#
|
161
|
+
# The output is a UTF-8 encoded string, without xml-entities.
|
162
|
+
def to_s
|
163
|
+
raise NotImplementedError.new
|
164
|
+
end
|
165
|
+
# Returns the underlying native element.
|
166
|
+
#
|
167
|
+
# You shouldn't need to use this, since doing so would void portability.
|
168
|
+
def native_element
|
169
|
+
@element
|
170
|
+
end
|
171
|
+
# Returns the node name of the current element.
|
172
|
+
def node_name
|
173
|
+
raise NotImplementedError.new
|
174
|
+
end
|
175
|
+
# Queries the document with XPath, relative to the current element.
|
176
|
+
#
|
177
|
+
# +ns+ Should be a Hash of prefix => namespace
|
178
|
+
#
|
179
|
+
# Returns a +NodeSelection+
|
180
|
+
#
|
181
|
+
# See add_namespace
|
182
|
+
def xpath(expression, ns = nil)
|
183
|
+
raise NotImplementedError.new
|
184
|
+
end
|
185
|
+
# Returns the outer XML for this element.
|
186
|
+
def to_xml
|
187
|
+
raise NotImplementedError.new
|
188
|
+
end
|
189
|
+
# Returns the outer XML for this element, preserving the original formatting.
|
190
|
+
def to_raw
|
191
|
+
raise NotImplementedError.new
|
192
|
+
end
|
193
|
+
# alias of +xpath+
|
194
|
+
def /(expression)
|
195
|
+
self.xpath(expression)
|
196
|
+
end
|
197
|
+
# Returns the attribute value of the underlying element.
|
198
|
+
#
|
199
|
+
# Shortcut for:
|
200
|
+
#
|
201
|
+
# (node/"@attribute_name").to_s
|
202
|
+
def [](attribute_name)
|
203
|
+
raise NotImplementedError.new
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Driver for +libxml+.
|
208
|
+
#
|
209
|
+
# http://libxml.rubyforge.org/
|
210
|
+
class LibXMLDriver
|
211
|
+
include XmlElement
|
212
|
+
def node_name
|
213
|
+
@element.name
|
214
|
+
end
|
215
|
+
def xpath(expression, ns = nil)
|
216
|
+
ns = {} if ns.nil?
|
217
|
+
ns = @namespaces.merge(ns)
|
218
|
+
assert_prefixes!(expression, ns)
|
219
|
+
NodeSelection.new(@element.find(expression, ns.map{|k,v| "#{k}:#{v}" }).to_a.map{|node| LibXMLDriver.new(node, ns) })
|
220
|
+
end
|
221
|
+
def [](attribute_name)
|
222
|
+
raise ArgumentError.new unless attribute_name.kind_of? String
|
223
|
+
@element[attribute_name]
|
224
|
+
end
|
225
|
+
def to_xml
|
226
|
+
@element.to_s(:indent => true)
|
227
|
+
end
|
228
|
+
def to_raw
|
229
|
+
@element.to_s(:indent => false)
|
230
|
+
end
|
231
|
+
def to_s
|
232
|
+
if @element.kind_of? LibXML::XML::Attr
|
233
|
+
@element.value
|
234
|
+
else
|
235
|
+
@element.content
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Driver for +REXML+
|
241
|
+
#
|
242
|
+
# http://www.germane-software.com/software/rexml/
|
243
|
+
class REXMLDriver
|
244
|
+
include XmlElement
|
245
|
+
def node_name
|
246
|
+
@element.name
|
247
|
+
end
|
248
|
+
def xpath(expression, ns = nil)
|
249
|
+
ns = {} if ns.nil?
|
250
|
+
ns = @namespaces.merge(ns)
|
251
|
+
assert_prefixes!(expression, ns)
|
252
|
+
NodeSelection.new(REXML::XPath.match(@element, expression, ns).map{|node| REXMLDriver.new(node, ns) })
|
253
|
+
end
|
254
|
+
def [](attribute_name)
|
255
|
+
raise ArgumentError.new unless attribute_name.kind_of? String
|
256
|
+
@element.attributes[attribute_name]
|
257
|
+
end
|
258
|
+
def to_xml
|
259
|
+
require 'rexml/formatters/pretty'
|
260
|
+
formatter = REXML::Formatters::Pretty.new
|
261
|
+
out = String.new
|
262
|
+
formatter.write(@element, out)
|
263
|
+
# patch for REXML's broken formatting
|
264
|
+
out.gsub(/>\n\s+([^<]+)\n\s+<\//, ">\\1</")
|
265
|
+
end
|
266
|
+
def to_raw
|
267
|
+
@element.to_s
|
268
|
+
end
|
269
|
+
def to_s
|
270
|
+
if @element.kind_of? REXML::Attribute
|
271
|
+
@element.value
|
272
|
+
else
|
273
|
+
@element.text
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Driver for +Nokogiri+
|
279
|
+
#
|
280
|
+
# http://nokogiri.rubyforge.org/nokogiri/
|
281
|
+
class NokogiriDriver
|
282
|
+
include XmlElement
|
283
|
+
def node_name
|
284
|
+
@element.name
|
285
|
+
end
|
286
|
+
def xpath(expression, ns = nil)
|
287
|
+
ns = {} if ns.nil?
|
288
|
+
ns = @namespaces.merge(ns)
|
289
|
+
assert_prefixes!(expression, ns)
|
290
|
+
NodeSelection.new(@element.xpath(expression, ns).map{|node| NokogiriDriver.new(node, ns) })
|
291
|
+
end
|
292
|
+
def [](attribute_name)
|
293
|
+
raise ArgumentError.new unless attribute_name.kind_of? String
|
294
|
+
@element[attribute_name]
|
295
|
+
end
|
296
|
+
def to_xml
|
297
|
+
@element.serialize(:encoding => 'UTF-8')
|
298
|
+
end
|
299
|
+
def to_raw
|
300
|
+
@element.serialize(:encoding => 'UTF-8', :save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
|
301
|
+
end
|
302
|
+
def to_s
|
303
|
+
if @element.kind_of?(Nokogiri::XML::Text) || @element.kind_of?(Nokogiri::XML::CDATA)
|
304
|
+
element = @element
|
305
|
+
elsif @element.kind_of?(Nokogiri::XML::Attr)
|
306
|
+
return @element.value
|
307
|
+
else
|
308
|
+
element = @element.children.first
|
309
|
+
end
|
310
|
+
return if element.nil?
|
311
|
+
# This looks messy because it is .. Nokogiri's interface is in a flux
|
312
|
+
if element.kind_of?(Nokogiri::XML::CDATA)
|
313
|
+
element.serialize(:encoding => 'UTF-8').gsub(/^<!\[CDATA\[/, "").gsub(/\]\]>$/, "")
|
314
|
+
else
|
315
|
+
element.serialize(:encoding => 'UTF-8').gsub('<', '<').gsub('>', '>').gsub('"', '"').gsub(''', "'").gsub('&', '&')
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|