handsoap 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|