moxml 0.1.3 → 0.1.4
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +48 -20
- data/Gemfile +1 -0
- data/LICENSE.md +33 -0
- data/README.adoc +32 -10
- data/lib/moxml/adapter/base.rb +12 -0
- data/lib/moxml/adapter/customized_rexml/formatter.rb +195 -0
- data/lib/moxml/adapter/nokogiri.rb +1 -1
- data/lib/moxml/adapter/oga.rb +21 -7
- data/lib/moxml/adapter/rexml.rb +458 -0
- data/lib/moxml/adapter.rb +1 -1
- data/lib/moxml/attribute.rb +2 -2
- data/lib/moxml/config.rb +1 -1
- data/lib/moxml/document_builder.rb +13 -17
- data/lib/moxml/element.rb +2 -2
- data/lib/moxml/namespace.rb +1 -1
- data/lib/moxml/version.rb +1 -1
- data/spec/moxml/adapter/rexml_spec.rb +14 -0
- data/spec/moxml/all_with_adapters_spec.rb +0 -2
- data/spec/support/shared_examples/declaration.rb +1 -0
- data/spec/support/shared_examples/edge_cases.rb +3 -3
- data/spec/support/shared_examples/element.rb +1 -1
- data/spec/support/shared_examples/integration.rb +2 -2
- data/spec/support/shared_examples/xml_adapter.rb +169 -7
- metadata +7 -3
@@ -0,0 +1,458 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require "rexml/document"
|
5
|
+
require "rexml/xpath"
|
6
|
+
require "set"
|
7
|
+
require_relative "customized_rexml/formatter"
|
8
|
+
|
9
|
+
module Moxml
|
10
|
+
module Adapter
|
11
|
+
class Rexml < Base
|
12
|
+
class << self
|
13
|
+
def parse(xml, options = {})
|
14
|
+
native_doc = begin
|
15
|
+
::REXML::Document.new(xml)
|
16
|
+
rescue ::REXML::ParseException => e
|
17
|
+
raise Moxml::ParseError.new(e.message, line: e.line) if options[:strict]
|
18
|
+
|
19
|
+
create_document
|
20
|
+
end
|
21
|
+
DocumentBuilder.new(Context.new(:rexml)).build(native_doc)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_document
|
25
|
+
::REXML::Document.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_native_element(name)
|
29
|
+
::REXML::Element.new(name.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_native_text(content)
|
33
|
+
::REXML::Text.new(content.to_s, true, nil)
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_native_cdata(content)
|
37
|
+
::REXML::CData.new(content.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_native_comment(content)
|
41
|
+
::REXML::Comment.new(content.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_native_processing_instruction(target, content)
|
45
|
+
# Clone strings to avoid frozen string errors
|
46
|
+
::REXML::Instruction.new(target.to_s.dup, content.to_s.dup)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_native_declaration(version, encoding, standalone)
|
50
|
+
::REXML::XMLDecl.new(version, encoding&.downcase, standalone)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_native_doctype(name, external_id, system_id)
|
54
|
+
return nil unless name
|
55
|
+
|
56
|
+
parts = [name]
|
57
|
+
if external_id
|
58
|
+
parts.concat(["PUBLIC", %("#{external_id}")])
|
59
|
+
parts << %("#{system_id}") if system_id
|
60
|
+
elsif system_id
|
61
|
+
parts.concat(["SYSTEM", %("#{system_id}")])
|
62
|
+
end
|
63
|
+
|
64
|
+
::REXML::DocType.new(parts.join(" "))
|
65
|
+
end
|
66
|
+
|
67
|
+
def set_root(doc, element)
|
68
|
+
doc.add_element(element)
|
69
|
+
end
|
70
|
+
|
71
|
+
def node_type(node)
|
72
|
+
case node
|
73
|
+
when ::REXML::Document then :document
|
74
|
+
when ::REXML::Element then :element
|
75
|
+
when ::REXML::CData then :cdata
|
76
|
+
when ::REXML::Text then :text
|
77
|
+
when ::REXML::Comment then :comment
|
78
|
+
when ::REXML::Instruction then :processing_instruction
|
79
|
+
when ::REXML::DocType then :doctype
|
80
|
+
when ::REXML::XMLDecl then :declaration
|
81
|
+
else :unknown
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_node_name(node, name)
|
86
|
+
case node
|
87
|
+
when ::REXML::Element
|
88
|
+
node.name = name.to_s
|
89
|
+
when ::REXML::Instruction
|
90
|
+
node.target = name.to_s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def node_name(node)
|
95
|
+
case node
|
96
|
+
when ::REXML::Element, ::REXML::DocType
|
97
|
+
node.name
|
98
|
+
when ::REXML::XMLDecl
|
99
|
+
"xml"
|
100
|
+
when ::REXML::Instruction
|
101
|
+
node.target
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def duplicate_node(node)
|
106
|
+
# Make a complete duplicate of the node
|
107
|
+
# https://stackoverflow.com/questions/23878384/why-the-original-element-got-changed-when-i-modify-the-copy-created-by-dup-meth
|
108
|
+
Marshal.load(Marshal.dump(node))
|
109
|
+
end
|
110
|
+
|
111
|
+
def children(node)
|
112
|
+
return [] unless node.respond_to?(:children)
|
113
|
+
|
114
|
+
# Get all children and filter out empty text nodes between elements
|
115
|
+
result = node.children.reject do |child|
|
116
|
+
child.is_a?(::REXML::Text) &&
|
117
|
+
child.to_s.strip.empty? &&
|
118
|
+
!(child.next_sibling.nil? && child.previous_sibling.nil?)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Ensure uniqueness by object_id to prevent duplicates
|
122
|
+
result.uniq(&:object_id)
|
123
|
+
end
|
124
|
+
|
125
|
+
def parent(node)
|
126
|
+
node.parent
|
127
|
+
end
|
128
|
+
|
129
|
+
def next_sibling(node)
|
130
|
+
current = node.next_sibling
|
131
|
+
|
132
|
+
# Skip empty text nodes and duplicates
|
133
|
+
seen = Set.new
|
134
|
+
while current
|
135
|
+
if current.is_a?(::REXML::Text) && current.to_s.strip.empty?
|
136
|
+
current = current.next_sibling
|
137
|
+
next
|
138
|
+
end
|
139
|
+
|
140
|
+
# Check for duplicates
|
141
|
+
if seen.include?(current.object_id)
|
142
|
+
current = current.next_sibling
|
143
|
+
next
|
144
|
+
end
|
145
|
+
|
146
|
+
seen.add(current.object_id)
|
147
|
+
break
|
148
|
+
end
|
149
|
+
|
150
|
+
current
|
151
|
+
end
|
152
|
+
|
153
|
+
def previous_sibling(node)
|
154
|
+
current = node.previous_sibling
|
155
|
+
|
156
|
+
# Skip empty text nodes and duplicates
|
157
|
+
seen = Set.new
|
158
|
+
while current
|
159
|
+
if current.is_a?(::REXML::Text) && current.to_s.strip.empty?
|
160
|
+
current = current.previous_sibling
|
161
|
+
next
|
162
|
+
end
|
163
|
+
|
164
|
+
# Check for duplicates
|
165
|
+
if seen.include?(current.object_id)
|
166
|
+
current = current.previous_sibling
|
167
|
+
next
|
168
|
+
end
|
169
|
+
|
170
|
+
seen.add(current.object_id)
|
171
|
+
break
|
172
|
+
end
|
173
|
+
|
174
|
+
current
|
175
|
+
end
|
176
|
+
|
177
|
+
def document(node)
|
178
|
+
node.document
|
179
|
+
end
|
180
|
+
|
181
|
+
def root(document)
|
182
|
+
document.root
|
183
|
+
end
|
184
|
+
|
185
|
+
def attributes(element)
|
186
|
+
return [] unless element.respond_to?(:attributes)
|
187
|
+
|
188
|
+
# Only return non-namespace attributes
|
189
|
+
element.attributes.values
|
190
|
+
.reject { |attr| attr.prefix.to_s.start_with?("xmlns") }
|
191
|
+
end
|
192
|
+
|
193
|
+
def attribute_element(attribute)
|
194
|
+
attribute.element
|
195
|
+
end
|
196
|
+
|
197
|
+
def set_attribute(element, name, value)
|
198
|
+
element.attributes[name&.to_s] = value
|
199
|
+
::REXML::Attribute.new(name&.to_s, value.to_s, element)
|
200
|
+
end
|
201
|
+
|
202
|
+
def set_attribute_name(attribute, name)
|
203
|
+
old_name = attribute.expanded_name
|
204
|
+
attribute.name = name
|
205
|
+
# Rexml doesn't change the keys of the attributes hash
|
206
|
+
element = attribute.element
|
207
|
+
element.attributes.delete(old_name)
|
208
|
+
element.attributes << attribute
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_attribute_value(attribute, value)
|
212
|
+
attribute.normalized = value
|
213
|
+
end
|
214
|
+
|
215
|
+
def get_attribute(element, name)
|
216
|
+
element.attributes.get_attribute(name)
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_attribute_value(element, name)
|
220
|
+
element.attributes[name]
|
221
|
+
end
|
222
|
+
|
223
|
+
def remove_attribute(element, name)
|
224
|
+
element.delete_attribute(name.to_s)
|
225
|
+
end
|
226
|
+
|
227
|
+
def add_child(element, child)
|
228
|
+
case child
|
229
|
+
when String
|
230
|
+
element.add_text(child)
|
231
|
+
else
|
232
|
+
element.add(child)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def add_previous_sibling(node, sibling)
|
237
|
+
parent = node.parent
|
238
|
+
# caveat: Rexml fails if children belong to the same parent and are already in a correct order
|
239
|
+
# example: "<root><a/><b/></root>"
|
240
|
+
# add_previous_sibling(node_b, node_a)
|
241
|
+
# result: "<root><b/><a/></root>"
|
242
|
+
# expected result: "<root><a/><b/></root>"
|
243
|
+
parent.insert_before(node, sibling)
|
244
|
+
end
|
245
|
+
|
246
|
+
def add_next_sibling(node, sibling)
|
247
|
+
parent = node.parent
|
248
|
+
parent.insert_after(node, sibling)
|
249
|
+
end
|
250
|
+
|
251
|
+
def remove(node)
|
252
|
+
node.remove
|
253
|
+
end
|
254
|
+
|
255
|
+
def replace(node, new_node)
|
256
|
+
node.replace_with(new_node)
|
257
|
+
end
|
258
|
+
|
259
|
+
def replace_children(element, children)
|
260
|
+
element.children.each(&:remove)
|
261
|
+
children.each { |child| element.add(child) }
|
262
|
+
end
|
263
|
+
|
264
|
+
def declaration_attribute(node, name)
|
265
|
+
case name
|
266
|
+
when "version"
|
267
|
+
node.version
|
268
|
+
when "encoding"
|
269
|
+
node.encoding
|
270
|
+
when "standalone"
|
271
|
+
node.standalone
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def set_declaration_attribute(node, name, value)
|
276
|
+
case name
|
277
|
+
when "version"
|
278
|
+
node.version = value
|
279
|
+
when "encoding"
|
280
|
+
node.encoding = value
|
281
|
+
when "standalone"
|
282
|
+
node.standalone = value
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def comment_content(node)
|
287
|
+
node.string
|
288
|
+
end
|
289
|
+
|
290
|
+
def set_comment_content(node, content)
|
291
|
+
node.string = content.to_s
|
292
|
+
end
|
293
|
+
|
294
|
+
def cdata_content(node)
|
295
|
+
node.value
|
296
|
+
end
|
297
|
+
|
298
|
+
def set_cdata_content(node, content)
|
299
|
+
node.value = content.to_s
|
300
|
+
end
|
301
|
+
|
302
|
+
def processing_instruction_target(node)
|
303
|
+
node.target
|
304
|
+
end
|
305
|
+
|
306
|
+
def processing_instruction_content(node)
|
307
|
+
node.content
|
308
|
+
end
|
309
|
+
|
310
|
+
def set_processing_instruction_content(node, content)
|
311
|
+
node.content = content.to_s
|
312
|
+
end
|
313
|
+
|
314
|
+
def text_content(node)
|
315
|
+
case node
|
316
|
+
when ::REXML::Text, ::REXML::CData
|
317
|
+
node.value.to_s
|
318
|
+
when ::REXML::Element
|
319
|
+
# Get all text nodes, filter out duplicates, and join
|
320
|
+
text_nodes = node.texts.uniq(&:object_id)
|
321
|
+
text_nodes.map(&:value).join
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def inner_text(node)
|
326
|
+
# Get direct text children only, filter duplicates
|
327
|
+
text_children = node.children
|
328
|
+
.select { |c| c.is_a?(::REXML::Text) }
|
329
|
+
.uniq(&:object_id)
|
330
|
+
text_children.map(&:value).join
|
331
|
+
end
|
332
|
+
|
333
|
+
def set_text_content(node, content)
|
334
|
+
case node
|
335
|
+
when ::REXML::Text, ::REXML::CData
|
336
|
+
node.value = content.to_s
|
337
|
+
when ::REXML::Element
|
338
|
+
# Remove existing text nodes to prevent duplicates
|
339
|
+
node.texts.each(&:remove)
|
340
|
+
# Add new text content
|
341
|
+
node.add_text(content.to_s)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
# add a namespace definition, keep the element name unchanged
|
346
|
+
def create_native_namespace(element, prefix, uri)
|
347
|
+
element.add_namespace(prefix.to_s, uri)
|
348
|
+
::REXML::Attribute.new(prefix.to_s, uri, element)
|
349
|
+
end
|
350
|
+
|
351
|
+
# add a namespace prefix to the element name AND a namespace definition
|
352
|
+
def set_namespace(element, ns)
|
353
|
+
prefix = ns.name.to_s.empty? ? "xmlns" : ns.name.to_s
|
354
|
+
element.add_namespace(prefix, ns.value) if element.respond_to?(:add_namespace)
|
355
|
+
element.name = "#{prefix}:#{element.name}"
|
356
|
+
owner = element.is_a?(::REXML::Attribute) ? element.element : element
|
357
|
+
::REXML::Attribute.new(prefix, ns.value, owner)
|
358
|
+
end
|
359
|
+
|
360
|
+
def namespace_prefix(node)
|
361
|
+
node.name unless node.name == "xmlns"
|
362
|
+
end
|
363
|
+
|
364
|
+
def namespace_uri(node)
|
365
|
+
node.value
|
366
|
+
end
|
367
|
+
|
368
|
+
def namespace(node)
|
369
|
+
prefix = node.prefix
|
370
|
+
uri = node.namespace(prefix)
|
371
|
+
return if prefix.to_s.empty? && uri.to_s.empty?
|
372
|
+
|
373
|
+
owner = node.is_a?(::REXML::Attribute) ? node.element : node
|
374
|
+
::REXML::Attribute.new(prefix, uri, owner)
|
375
|
+
end
|
376
|
+
|
377
|
+
def namespace_definitions(node)
|
378
|
+
node.namespaces.map do |prefix, uri|
|
379
|
+
::REXML::Attribute.new(prefix.to_s, uri, node)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def prepare_xpath_namespaces(node)
|
384
|
+
ns = {}
|
385
|
+
|
386
|
+
# Get all namespace definitions in scope
|
387
|
+
all_ns = namespace_definitions(node)
|
388
|
+
|
389
|
+
# Convert to XPath-friendly format
|
390
|
+
all_ns.each do |prefix, uri|
|
391
|
+
if prefix.to_s.empty?
|
392
|
+
ns["xmlns"] = uri
|
393
|
+
else
|
394
|
+
ns[prefix] = uri
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
ns
|
399
|
+
end
|
400
|
+
|
401
|
+
def xpath(node, expression, _namespaces = {})
|
402
|
+
node.get_elements(expression).to_a
|
403
|
+
rescue ::REXML::ParseException => e
|
404
|
+
raise Moxml::XPathError, e.message
|
405
|
+
end
|
406
|
+
|
407
|
+
def at_xpath(node, expression, namespaces = {})
|
408
|
+
results = xpath(node, expression, namespaces)
|
409
|
+
results.first
|
410
|
+
end
|
411
|
+
|
412
|
+
def serialize(node, options = {})
|
413
|
+
output = String.new
|
414
|
+
|
415
|
+
if node.is_a?(::REXML::Document)
|
416
|
+
# Always include XML declaration
|
417
|
+
decl = node.xml_decl || ::REXML::XMLDecl.new("1.0", options[:encoding] || "UTF-8")
|
418
|
+
decl.encoding = options[:encoding] if options[:encoding]
|
419
|
+
output << "<?xml"
|
420
|
+
output << %( version="#{decl.version}") if decl.version
|
421
|
+
output << %( encoding="#{decl.encoding}") if decl.encoding
|
422
|
+
output << %( standalone="#{decl.standalone}") if decl.standalone
|
423
|
+
output << "?>"
|
424
|
+
# output << "\n"
|
425
|
+
|
426
|
+
if node.doctype
|
427
|
+
node.doctype.write(output)
|
428
|
+
# output << "\n"
|
429
|
+
end
|
430
|
+
|
431
|
+
# Write processing instructions
|
432
|
+
node.children.each do |child|
|
433
|
+
if child.is_a?(::REXML::Instruction)
|
434
|
+
child.write(output)
|
435
|
+
# output << "\n"
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
write_with_formatter(node.root, output, options[:indent] || 2) if node.root
|
440
|
+
else
|
441
|
+
write_with_formatter(node, output, options[:indent] || 2)
|
442
|
+
end
|
443
|
+
|
444
|
+
output.strip
|
445
|
+
end
|
446
|
+
|
447
|
+
private
|
448
|
+
|
449
|
+
def write_with_formatter(node, output, indent = 2)
|
450
|
+
formatter = ::Moxml::Adapter::CustomizedRexml::Formatter.new(
|
451
|
+
indentation: indent, self_close_empty: false
|
452
|
+
)
|
453
|
+
formatter.write(node, output)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
data/lib/moxml/adapter.rb
CHANGED
data/lib/moxml/attribute.rb
CHANGED
@@ -7,7 +7,7 @@ module Moxml
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def name=(new_name)
|
10
|
-
@native
|
10
|
+
adapter.set_attribute_name(@native, new_name)
|
11
11
|
end
|
12
12
|
|
13
13
|
def value
|
@@ -15,7 +15,7 @@ module Moxml
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def value=(new_value)
|
18
|
-
@native
|
18
|
+
adapter.set_attribute_value(@native, new_value)
|
19
19
|
end
|
20
20
|
|
21
21
|
def namespace
|
data/lib/moxml/config.rb
CHANGED
@@ -18,7 +18,6 @@ module Moxml
|
|
18
18
|
private
|
19
19
|
|
20
20
|
def visit_node(node)
|
21
|
-
node.respond_to?(:name) ? node.name : node
|
22
21
|
method_name = "visit_#{node_type(node)}"
|
23
22
|
return unless respond_to?(method_name, true)
|
24
23
|
|
@@ -28,41 +27,38 @@ module Moxml
|
|
28
27
|
def visit_document(doc)
|
29
28
|
@node_stack.push(@current_doc)
|
30
29
|
visit_children(doc)
|
31
|
-
@node_stack.
|
30
|
+
@node_stack.clear
|
32
31
|
end
|
33
32
|
|
34
33
|
def visit_element(node)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
@node_stack.push(element)
|
34
|
+
childless_node = adapter.duplicate_node(node)
|
35
|
+
adapter.replace_children(childless_node, [])
|
36
|
+
element = Element.new(childless_node, context)
|
37
|
+
@node_stack.last.add_child(element)
|
38
|
+
|
39
|
+
@node_stack.push(element) # add a parent for its children
|
43
40
|
visit_children(node)
|
44
|
-
@node_stack.pop
|
45
|
-
element
|
41
|
+
@node_stack.pop # remove the parent
|
46
42
|
end
|
47
43
|
|
48
44
|
def visit_text(node)
|
49
|
-
@node_stack.last
|
45
|
+
@node_stack.last&.add_child(Text.new(node, context))
|
50
46
|
end
|
51
47
|
|
52
48
|
def visit_cdata(node)
|
53
|
-
@node_stack.last
|
49
|
+
@node_stack.last&.add_child(Cdata.new(node, context))
|
54
50
|
end
|
55
51
|
|
56
52
|
def visit_comment(node)
|
57
|
-
@node_stack.last
|
53
|
+
@node_stack.last&.add_child(Comment.new(node, context))
|
58
54
|
end
|
59
55
|
|
60
56
|
def visit_processing_instruction(node)
|
61
|
-
@node_stack.last
|
57
|
+
@node_stack.last&.add_child(ProcessingInstruction.new(node, context))
|
62
58
|
end
|
63
59
|
|
64
60
|
def visit_doctype(node)
|
65
|
-
@node_stack.last
|
61
|
+
@node_stack.last&.add_child(Doctype.new(node, context))
|
66
62
|
end
|
67
63
|
|
68
64
|
def visit_children(node)
|
data/lib/moxml/element.rb
CHANGED
@@ -87,8 +87,8 @@ module Moxml
|
|
87
87
|
adapter.inner_xml(@native)
|
88
88
|
end
|
89
89
|
|
90
|
-
def inner_xml=(
|
91
|
-
doc = context.parse("<root>#{
|
90
|
+
def inner_xml=(xml)
|
91
|
+
doc = context.parse("<root>#{xml}</root>")
|
92
92
|
adapter.replace_children(@native, doc.root.children.map(&:native))
|
93
93
|
end
|
94
94
|
|
data/lib/moxml/namespace.rb
CHANGED
data/lib/moxml/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rexml"
|
4
|
+
require "moxml/adapter/rexml"
|
5
|
+
|
6
|
+
RSpec.describe Moxml::Adapter::Rexml do
|
7
|
+
around do |example|
|
8
|
+
Moxml.with_config(:rexml, true, "UTF-8") do
|
9
|
+
example.run
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it_behaves_like "xml adapter"
|
14
|
+
end
|
@@ -29,8 +29,6 @@ RSpec.describe "Test all shared examples" do
|
|
29
29
|
]
|
30
30
|
|
31
31
|
Moxml::Adapter::AVALIABLE_ADAPTERS.each do |adapter_name|
|
32
|
-
# [:nokogiri].each do |adapter_name|
|
33
|
-
# [:oga].each do |adapter_name|
|
34
32
|
context "with #{adapter_name}" do
|
35
33
|
around do |example|
|
36
34
|
Moxml.with_config(adapter_name) do
|
@@ -36,6 +36,7 @@ RSpec.shared_examples "Moxml::Declaration" do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "normalizes encoding" do
|
39
|
+
pending("Rexml Encoding upcases the string") if Moxml.new.config.adapter.name.include?("Rexml")
|
39
40
|
declaration.encoding = "utf-8"
|
40
41
|
expect(declaration.encoding).to eq("utf-8")
|
41
42
|
end
|
@@ -86,7 +86,7 @@ RSpec.shared_examples "Moxml Edge Cases" do
|
|
86
86
|
|
87
87
|
doc = context.parse(xml)
|
88
88
|
grandchild = doc.at_xpath("//xmlns:grandchild", "xmlns" => "")
|
89
|
-
expect(grandchild.
|
89
|
+
expect(grandchild.namespaces.first.uri).to eq("")
|
90
90
|
end
|
91
91
|
|
92
92
|
it "handles recursive namespace definitions" do
|
@@ -143,13 +143,13 @@ RSpec.shared_examples "Moxml Edge Cases" do
|
|
143
143
|
current = doc.create_element("root")
|
144
144
|
doc.add_child(current)
|
145
145
|
|
146
|
-
|
146
|
+
10.times do |i|
|
147
147
|
nested = doc.create_element("nested#{i}")
|
148
148
|
current.add_child(nested)
|
149
149
|
current = nested
|
150
150
|
end
|
151
151
|
|
152
|
-
expect(doc.to_xml).to include("<
|
152
|
+
expect(doc.to_xml).to include("<nested9>")
|
153
153
|
end
|
154
154
|
|
155
155
|
it "handles large number of siblings" do
|
@@ -55,7 +55,7 @@ RSpec.shared_examples "Moxml::Element" do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it "sets namespace" do
|
58
|
-
ns = element.add_namespace("x", "http://example.org").
|
58
|
+
ns = element.add_namespace("x", "http://example.org").namespaces.first
|
59
59
|
element.namespace = ns
|
60
60
|
expect(element.namespace).to eq(ns)
|
61
61
|
end
|
@@ -111,7 +111,7 @@ RSpec.shared_examples "Moxml Integration" do
|
|
111
111
|
# Move nodes
|
112
112
|
b_node = doc.at_xpath("//b")
|
113
113
|
a_node = doc.at_xpath("//a")
|
114
|
-
|
114
|
+
a_node.add_previous_sibling(b_node)
|
115
115
|
|
116
116
|
# Add nodes
|
117
117
|
c_node = doc.create_element("c")
|
@@ -125,7 +125,7 @@ RSpec.shared_examples "Moxml Integration" do
|
|
125
125
|
b_node.add_child(doc.create_comment(" comment "))
|
126
126
|
b_node.add_child(doc.create_cdata("<tag>"))
|
127
127
|
|
128
|
-
expect(doc.root.children.map(&:name)).to eq(%w[
|
128
|
+
expect(doc.root.children.map(&:name)).to eq(%w[b c a])
|
129
129
|
expect(doc.to_xml).to include(
|
130
130
|
'<root id="main">',
|
131
131
|
"<b>2<!-- comment --><![CDATA[<tag>]]></b>"
|