moxml 0.1.4 → 0.1.6
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/.gitignore +0 -1
- data/.rubocop_todo.yml +2 -2
- data/Gemfile +2 -0
- data/README.adoc +71 -21
- data/lib/moxml/adapter/base.rb +8 -2
- data/lib/moxml/adapter/customized_ox/attribute.rb +29 -0
- data/lib/moxml/adapter/customized_ox/namespace.rb +34 -0
- data/lib/moxml/adapter/customized_ox/text.rb +12 -0
- data/lib/moxml/adapter/customized_rexml/formatter.rb +3 -3
- data/lib/moxml/adapter/nokogiri.rb +3 -1
- data/lib/moxml/adapter/oga.rb +4 -2
- data/lib/moxml/adapter/ox.rb +238 -92
- data/lib/moxml/adapter/rexml.rb +10 -6
- data/lib/moxml/adapter.rb +1 -1
- data/lib/moxml/cdata.rb +0 -4
- data/lib/moxml/comment.rb +0 -4
- data/lib/moxml/context.rb +2 -2
- data/lib/moxml/doctype.rb +1 -5
- data/lib/moxml/document.rb +1 -1
- data/lib/moxml/document_builder.rb +1 -1
- data/lib/moxml/element.rb +2 -1
- data/lib/moxml/namespace.rb +4 -0
- data/lib/moxml/node.rb +17 -2
- data/lib/moxml/node_set.rb +8 -1
- data/lib/moxml/processing_instruction.rb +0 -4
- data/lib/moxml/text.rb +0 -4
- data/lib/moxml/version.rb +1 -1
- data/lib/ox/node.rb +9 -0
- data/spec/fixtures/small.xml +1 -0
- data/spec/moxml/all_with_adapters_spec.rb +2 -1
- data/spec/support/shared_examples/builder.rb +19 -2
- data/spec/support/shared_examples/cdata.rb +7 -5
- data/spec/support/shared_examples/declaration.rb +16 -4
- data/spec/support/shared_examples/doctype.rb +2 -1
- data/spec/support/shared_examples/document.rb +10 -0
- data/spec/support/shared_examples/edge_cases.rb +6 -0
- data/spec/support/shared_examples/element.rb +4 -0
- data/spec/support/shared_examples/examples/benchmark_spec.rb +51 -0
- data/spec/support/shared_examples/examples/memory.rb +30 -17
- data/spec/support/shared_examples/examples/readme_examples.rb +5 -0
- data/spec/support/shared_examples/examples/thread_safety.rb +2 -0
- data/spec/support/shared_examples/examples/xpath.rb +34 -3
- data/spec/support/shared_examples/integration.rb +4 -0
- data/spec/support/shared_examples/namespace.rb +16 -0
- data/spec/support/shared_examples/node.rb +4 -0
- data/spec/support/shared_examples/node_set.rb +20 -0
- data/spec/support/shared_examples/processing_instruction.rb +1 -1
- data/spec/support/shared_examples/text.rb +2 -1
- metadata +8 -2
data/lib/moxml/adapter/ox.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "base"
|
4
|
+
# before ox so that all Ox classes inherit the monkey-patched Node
|
5
|
+
require_relative "../../ox/node"
|
4
6
|
require "ox"
|
7
|
+
require_relative "customized_ox/text"
|
8
|
+
require_relative "customized_ox/attribute"
|
9
|
+
require_relative "customized_ox/namespace"
|
5
10
|
|
6
11
|
module Moxml
|
7
12
|
module Adapter
|
@@ -30,8 +35,9 @@ module Moxml
|
|
30
35
|
DocumentBuilder.new(Context.new(:ox)).build(native_doc)
|
31
36
|
end
|
32
37
|
|
33
|
-
def create_document
|
34
|
-
|
38
|
+
def create_document(native_doc = nil)
|
39
|
+
attrs = native_doc&.attributes || {}
|
40
|
+
::Ox::Document.new(**attrs)
|
35
41
|
end
|
36
42
|
|
37
43
|
def create_native_element(name)
|
@@ -52,63 +58,94 @@ module Moxml
|
|
52
58
|
::Ox::Comment.new(content)
|
53
59
|
end
|
54
60
|
|
61
|
+
def create_native_doctype(name, external_id, system_id)
|
62
|
+
::Ox::DocType.new(
|
63
|
+
"#{name} PUBLIC \"#{external_id}\" \"#{system_id}\""
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
55
67
|
def create_native_processing_instruction(target, content)
|
56
|
-
inst = ::Ox::
|
57
|
-
inst
|
68
|
+
inst = ::Ox::Instruct.new(target)
|
69
|
+
set_processing_instruction_content(inst, content)
|
58
70
|
inst
|
59
71
|
end
|
60
72
|
|
61
|
-
|
62
|
-
def create_native_declaration2(version, encoding, standalone)
|
73
|
+
def create_native_declaration(version, encoding, standalone)
|
63
74
|
inst = ::Ox::Instruct.new("xml")
|
64
|
-
inst
|
75
|
+
set_attribute(inst, "version", version)
|
76
|
+
set_attribute(inst, "encoding", encoding)
|
77
|
+
set_attribute(inst, "standalone", standalone)
|
65
78
|
inst
|
66
79
|
end
|
67
80
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
81
|
+
def declaration_attribute(declaration, attr_name)
|
82
|
+
get_attribute_value(declaration, attr_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_declaration_attribute(declaration, attr_name, value)
|
86
|
+
set_attribute(declaration, attr_name, value)
|
74
87
|
end
|
75
88
|
|
76
89
|
def create_native_namespace(element, prefix, uri)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
[prefix, uri]
|
90
|
+
ns = ::Moxml::Adapter::CustomizedOx::Namespace.new(prefix, uri, element)
|
91
|
+
set_attribute(element, ns.expanded_prefix, uri)
|
92
|
+
ns
|
81
93
|
end
|
82
94
|
|
83
95
|
def set_namespace(element, ns)
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
96
|
+
return unless element.respond_to?(:name)
|
97
|
+
|
98
|
+
prefix = ns.prefix
|
99
|
+
# attributes don't have attributes but can have a namespace prefix
|
100
|
+
set_attribute(element, ns.expanded_prefix, ns.uri) if element.respond_to?(:attributes)
|
101
|
+
element.name = [prefix, element.name.delete_prefix("xmlns:")].compact.join(":")
|
102
|
+
namespace(element)
|
88
103
|
end
|
89
104
|
|
90
105
|
def namespace(element)
|
91
|
-
|
106
|
+
prefix =
|
107
|
+
if element.respond_to?(:prefix)
|
108
|
+
# attribute
|
109
|
+
element.prefix
|
110
|
+
elsif element.name.include?(":")
|
111
|
+
element.name.split(":").first
|
112
|
+
end
|
113
|
+
attr_name = ["xmlns", prefix].compact.join(":")
|
92
114
|
|
93
|
-
|
94
|
-
|
115
|
+
([element] + ancestors(element)).each do |node|
|
116
|
+
next unless node.respond_to?(:attributes) && node.attributes
|
95
117
|
|
96
|
-
|
97
|
-
|
118
|
+
if node[attr_name]
|
119
|
+
return ::Moxml::Adapter::CustomizedOx::Namespace.new(
|
120
|
+
prefix, node[attr_name], element
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def ancestors(node)
|
129
|
+
return [] unless (parent = parent(node))
|
130
|
+
|
131
|
+
[parent] + ancestors(parent)
|
98
132
|
end
|
99
133
|
|
100
134
|
def processing_instruction_target(node)
|
101
|
-
node.
|
135
|
+
node.target
|
102
136
|
end
|
103
137
|
|
104
138
|
def node_type(node)
|
105
139
|
case node
|
106
140
|
when ::Ox::Document then :document
|
107
|
-
when String then :text
|
141
|
+
when ::Moxml::Adapter::CustomizedOx::Text, String then :text
|
108
142
|
when ::Ox::CData then :cdata
|
109
143
|
when ::Ox::Comment then :comment
|
110
144
|
when ::Ox::Instruct then :processing_instruction
|
111
145
|
when ::Ox::Element then :element
|
146
|
+
when ::Ox::DocType then :doctype
|
147
|
+
when ::Moxml::Adapter::CustomizedOx::Namespace then :banespace
|
148
|
+
when ::Moxml::Adapter::CustomizedOx::Attribute then :attribute
|
112
149
|
else :unknown
|
113
150
|
end
|
114
151
|
end
|
@@ -120,8 +157,40 @@ module Moxml
|
|
120
157
|
end
|
121
158
|
|
122
159
|
def set_node_name(node, name)
|
123
|
-
|
124
|
-
|
160
|
+
if node.respond_to?(:name=)
|
161
|
+
node.name = name
|
162
|
+
elsif node.respond_to?(:value=)
|
163
|
+
node.value = name
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def duplicate_node(node)
|
168
|
+
Marshal.load(Marshal.dump(node))
|
169
|
+
end
|
170
|
+
|
171
|
+
def patch_node(node, parent = nil)
|
172
|
+
new_node =
|
173
|
+
case node
|
174
|
+
# it can be either attribute or namespace
|
175
|
+
when Array then ::Moxml::Adapter::CustomizedOx::Attribute.new(node.first, node.last)
|
176
|
+
when Hash then ::Moxml::Adapter::CustomizedOx::Attribute.new(node.keys.first, node.values.first)
|
177
|
+
when String then ::Moxml::Adapter::CustomizedOx::Text.new(node)
|
178
|
+
else node
|
179
|
+
end
|
180
|
+
|
181
|
+
new_node.parent = parent if new_node.respond_to?(:parent)
|
182
|
+
|
183
|
+
new_node
|
184
|
+
end
|
185
|
+
|
186
|
+
def unpatch_node(node)
|
187
|
+
case node
|
188
|
+
# it can be either attribute or namespace
|
189
|
+
when ::Moxml::Adapter::CustomizedOx::Attribute then [node.name, node.value]
|
190
|
+
# when ::Moxml::Adapter::CustomizedOx::Attribute then { node.name => node.value }
|
191
|
+
when ::Moxml::Adapter::CustomizedOx::Text then node.value
|
192
|
+
else node
|
193
|
+
end
|
125
194
|
end
|
126
195
|
|
127
196
|
def children(node)
|
@@ -135,19 +204,19 @@ module Moxml
|
|
135
204
|
end
|
136
205
|
|
137
206
|
def next_sibling(node)
|
138
|
-
return unless (parent = parent
|
207
|
+
return unless (parent = node.parent)
|
139
208
|
|
140
209
|
siblings = parent.nodes
|
141
|
-
idx = siblings.index(node)
|
142
|
-
idx ? siblings[idx + 1] : nil
|
210
|
+
idx = siblings.index(unpatch_node(node))
|
211
|
+
idx ? patch_node(siblings[idx + 1], parent) : nil
|
143
212
|
end
|
144
213
|
|
145
214
|
def previous_sibling(node)
|
146
215
|
return unless (parent = parent(node))
|
147
216
|
|
148
217
|
siblings = parent.nodes
|
149
|
-
idx = siblings.index(node)
|
150
|
-
idx&.positive? ? siblings[idx - 1] : nil
|
218
|
+
idx = siblings.index(unpatch_node(node))
|
219
|
+
idx&.positive? ? patch_node(siblings[idx - 1], parent) : nil
|
151
220
|
end
|
152
221
|
|
153
222
|
def document(node)
|
@@ -161,74 +230,153 @@ module Moxml
|
|
161
230
|
end
|
162
231
|
|
163
232
|
def attributes(element)
|
164
|
-
return
|
233
|
+
return [] unless element.respond_to?(:attributes) && element.attributes
|
165
234
|
|
166
|
-
element.attributes.
|
235
|
+
element.attributes.map do |name, value|
|
236
|
+
next if name.start_with?("xmlns")
|
237
|
+
|
238
|
+
::Moxml::Adapter::CustomizedOx::Attribute.new(
|
239
|
+
name, value, element
|
240
|
+
)
|
241
|
+
end.compact
|
242
|
+
end
|
243
|
+
|
244
|
+
def attribute_element(attribute)
|
245
|
+
attribute.parent
|
167
246
|
end
|
168
247
|
|
169
248
|
def set_attribute(element, name, value)
|
170
249
|
element.attributes ||= {}
|
171
|
-
|
250
|
+
if value.nil?
|
251
|
+
# Ox converts all values to strings
|
252
|
+
remove_attribute(element, name)
|
253
|
+
else
|
254
|
+
element.attributes[name.to_s] = value
|
255
|
+
end
|
256
|
+
|
257
|
+
::Moxml::Adapter::CustomizedOx::Attribute.new(
|
258
|
+
name.to_s, value&.to_s, element
|
259
|
+
)
|
260
|
+
end
|
261
|
+
|
262
|
+
def set_attribute_name(attribute, name)
|
263
|
+
old_name = attribute.name
|
264
|
+
attribute.name = name.to_s
|
265
|
+
# Ox doesn't change the keys of the attributes hash
|
266
|
+
element = attribute.parent
|
267
|
+
element.attributes.delete(old_name)
|
268
|
+
element.attributes[name] = attribute.value
|
269
|
+
end
|
270
|
+
|
271
|
+
def set_attribute_value(attribute, new_value)
|
272
|
+
if new_value.nil?
|
273
|
+
# Ox converts all values to strings
|
274
|
+
remove_attribute(attribute.parent, attribute.name)
|
275
|
+
else
|
276
|
+
attribute.value = new_value
|
277
|
+
attribute.parent.attributes[attribute.name] = new_value
|
278
|
+
end
|
172
279
|
end
|
173
280
|
|
174
281
|
def get_attribute(element, name)
|
175
|
-
return
|
282
|
+
return unless element.respond_to?(:attributes) && element.attributes
|
283
|
+
return unless element.attributes.key?(name.to_s) || element.attributes.key?(name.to_s.to_sym)
|
284
|
+
|
285
|
+
::Moxml::Adapter::CustomizedOx::Attribute.new(
|
286
|
+
name.to_s, element.attributes[name], element
|
287
|
+
)
|
288
|
+
end
|
176
289
|
|
177
|
-
|
290
|
+
def get_attribute_value(element, name)
|
291
|
+
element[name]
|
178
292
|
end
|
179
293
|
|
180
294
|
def remove_attribute(element, name)
|
181
295
|
return unless element.respond_to?(:attributes) && element.attributes
|
182
296
|
|
183
297
|
element.attributes.delete(name.to_s)
|
298
|
+
element.attributes.delete(name.to_s.to_sym)
|
184
299
|
end
|
185
300
|
|
186
301
|
def add_child(element, child)
|
302
|
+
child.parent = element if child.respond_to?(:parent)
|
187
303
|
element.nodes ||= []
|
188
|
-
puts "Add child #{child} for #{element.name}: #{element.nodes.count}"
|
189
304
|
element.nodes << child
|
190
305
|
end
|
191
306
|
|
192
307
|
def add_previous_sibling(node, sibling)
|
193
|
-
return unless parent(node)
|
308
|
+
return unless (parent = parent(node))
|
194
309
|
|
195
|
-
|
196
|
-
|
310
|
+
if sibling.respond_to?(:parent)
|
311
|
+
sibling.parent&.nodes&.delete(sibling)
|
312
|
+
sibling.parent = parent
|
313
|
+
end
|
314
|
+
idx = parent.nodes.index(node)
|
315
|
+
parent.nodes.insert(idx, sibling) if idx
|
197
316
|
end
|
198
317
|
|
199
318
|
def add_next_sibling(node, sibling)
|
200
|
-
return unless parent(node)
|
319
|
+
return unless (parent = parent(node))
|
201
320
|
|
202
|
-
|
203
|
-
|
321
|
+
if sibling.respond_to?(:parent)
|
322
|
+
sibling.parent&.nodes&.delete(sibling)
|
323
|
+
sibling.parent = parent
|
324
|
+
end
|
325
|
+
idx = parent.nodes.index(node)
|
326
|
+
parent.nodes.insert(idx + 1, sibling) if idx
|
204
327
|
end
|
205
328
|
|
206
329
|
def remove(node)
|
330
|
+
return node.clear if node.is_a?(String)
|
331
|
+
|
207
332
|
return unless parent(node)
|
208
333
|
|
209
|
-
node.
|
334
|
+
parent(node).nodes.delete(node)
|
210
335
|
end
|
211
336
|
|
212
337
|
def replace(node, new_node)
|
213
|
-
return
|
338
|
+
return node.replace(new_node) if node.is_a?(String) && new_node.is_a?(String)
|
339
|
+
# There are other cases:
|
340
|
+
# when node is a String and new_node isn't
|
341
|
+
# when node isn't a String, and new_node is a String
|
342
|
+
|
343
|
+
return unless (parent = parent(node))
|
214
344
|
|
215
|
-
|
216
|
-
|
345
|
+
new_node.parent = parent if new_node.respond_to?(:parent)
|
346
|
+
idx = parent.nodes.index(node)
|
347
|
+
parent.nodes[idx] = new_node if idx
|
217
348
|
end
|
218
349
|
|
219
350
|
def replace_children(node, new_children)
|
220
351
|
node.remove_children_by_path("*")
|
221
|
-
new_children.each
|
352
|
+
new_children.each do |child|
|
353
|
+
child.parent = node if child.respond_to?(:parent)
|
354
|
+
node << child
|
355
|
+
end
|
222
356
|
node
|
223
357
|
end
|
224
358
|
|
225
359
|
def text_content(node)
|
226
|
-
|
360
|
+
case node
|
361
|
+
when String then node.to_s
|
362
|
+
when ::Moxml::Adapter::CustomizedOx::Text then node.value
|
363
|
+
else
|
364
|
+
node.nodes.map do |n|
|
365
|
+
text_content(n)
|
366
|
+
end.join
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def inner_text(node)
|
371
|
+
return "" unless node.respond_to?(:nodes)
|
372
|
+
|
373
|
+
node.nodes.select { _1.is_a?(String) }.join
|
227
374
|
end
|
228
375
|
|
229
376
|
def set_text_content(node, content)
|
230
|
-
|
231
|
-
|
377
|
+
case node
|
378
|
+
when String then node.replace(content.to_s)
|
379
|
+
when ::Ox::Element then node.replace_text(content.to_s)
|
232
380
|
else
|
233
381
|
node.value = content.to_s
|
234
382
|
end
|
@@ -251,48 +399,60 @@ module Moxml
|
|
251
399
|
end
|
252
400
|
|
253
401
|
def processing_instruction_content(node)
|
254
|
-
node.
|
402
|
+
node.content.to_s
|
255
403
|
end
|
256
404
|
|
257
405
|
def set_processing_instruction_content(node, content)
|
258
|
-
node.
|
406
|
+
node.content = content.to_s
|
407
|
+
end
|
408
|
+
|
409
|
+
def namespace_prefix(namespace)
|
410
|
+
namespace.prefix
|
411
|
+
end
|
412
|
+
|
413
|
+
def namespace_uri(namespace)
|
414
|
+
namespace.uri
|
259
415
|
end
|
260
416
|
|
261
417
|
def namespace_definitions(node)
|
262
|
-
|
418
|
+
([node] + ancestors(node)).reverse.each_with_object({}) do |n, namespaces|
|
419
|
+
next unless n.respond_to?(:attributes) && n.attributes
|
263
420
|
|
264
|
-
|
265
|
-
|
421
|
+
n.attributes.each do |name, value|
|
422
|
+
next unless name.to_s.start_with?("xmlns")
|
266
423
|
|
267
|
-
|
268
|
-
|
269
|
-
|
424
|
+
namespaces[name] = ::Moxml::Adapter::CustomizedOx::Namespace.new(
|
425
|
+
name, value, n
|
426
|
+
)
|
427
|
+
end
|
428
|
+
end.values
|
270
429
|
end
|
271
430
|
|
272
|
-
def xpath(node, expression,
|
273
|
-
#
|
274
|
-
|
275
|
-
traverse(node) do |n|
|
276
|
-
results << n if matches_xpath?(n, expression, namespaces)
|
277
|
-
end
|
278
|
-
results
|
431
|
+
def xpath(node, expression, _namespaces = {})
|
432
|
+
# locate has a different syntax
|
433
|
+
node.locate(expression)
|
279
434
|
end
|
280
435
|
|
281
436
|
def at_xpath(node, expression, namespaces = {})
|
282
|
-
|
283
|
-
return n if matches_xpath?(n, expression, namespaces)
|
284
|
-
end
|
285
|
-
nil
|
437
|
+
xpath(node, expression, namespaces)&.first
|
286
438
|
end
|
287
439
|
|
288
440
|
def serialize(node, options = {})
|
441
|
+
output = ""
|
442
|
+
if node.is_a?(::Ox::Document)
|
443
|
+
# add declaration
|
444
|
+
decl = create_native_declaration(node[:version], node[:encoding], node[:standalone])
|
445
|
+
output = ::Ox.dump(::Ox::Document.new << decl).strip
|
446
|
+
end
|
447
|
+
|
289
448
|
ox_options = {
|
290
|
-
indent: options[:indent] || -1,
|
291
|
-
with_xml: true,
|
449
|
+
indent: -1, # options[:indent] || -1, # indent is a beast
|
450
|
+
# with_xml: true,
|
292
451
|
with_instructions: true,
|
293
|
-
encoding: options[:encoding]
|
452
|
+
encoding: options[:encoding],
|
453
|
+
no_empty: options[:expand_empty]
|
294
454
|
}
|
295
|
-
::Ox.dump(node, ox_options)
|
455
|
+
output + ::Ox.dump(node, ox_options)
|
296
456
|
end
|
297
457
|
|
298
458
|
private
|
@@ -305,20 +465,6 @@ module Moxml
|
|
305
465
|
|
306
466
|
node.nodes&.each { |child| traverse(child, &block) }
|
307
467
|
end
|
308
|
-
|
309
|
-
def matches_xpath?(node, expression, _namespaces = {})
|
310
|
-
case expression
|
311
|
-
when %r{//(\w+)}
|
312
|
-
node.is_a?(::Ox::Element) && node.value == ::Regexp.last_match(1)
|
313
|
-
when %r{//(\w+)\[@(\w+)='([^']+)'\]}
|
314
|
-
node.is_a?(::Ox::Element) &&
|
315
|
-
node.value == ::Regexp.last_match(1) &&
|
316
|
-
node.attributes &&
|
317
|
-
node.attributes[::Regexp.last_match(2)] == ::Regexp.last_match(3)
|
318
|
-
else
|
319
|
-
false
|
320
|
-
end
|
321
|
-
end
|
322
468
|
end
|
323
469
|
end
|
324
470
|
end
|
data/lib/moxml/adapter/rexml.rb
CHANGED
@@ -21,7 +21,7 @@ module Moxml
|
|
21
21
|
DocumentBuilder.new(Context.new(:rexml)).build(native_doc)
|
22
22
|
end
|
23
23
|
|
24
|
-
def create_document
|
24
|
+
def create_document(_native_doc = nil)
|
25
25
|
::REXML::Document.new
|
26
26
|
end
|
27
27
|
|
@@ -75,6 +75,8 @@ module Moxml
|
|
75
75
|
when ::REXML::CData then :cdata
|
76
76
|
when ::REXML::Text then :text
|
77
77
|
when ::REXML::Comment then :comment
|
78
|
+
when ::REXML::Attribute then :attribute # but in fact it may be a namespace as well
|
79
|
+
when ::REXML::Namespace then :namespace # we don't use this one
|
78
80
|
when ::REXML::Instruction then :processing_instruction
|
79
81
|
when ::REXML::DocType then :doctype
|
80
82
|
when ::REXML::XMLDecl then :declaration
|
@@ -325,7 +327,7 @@ module Moxml
|
|
325
327
|
def inner_text(node)
|
326
328
|
# Get direct text children only, filter duplicates
|
327
329
|
text_children = node.children
|
328
|
-
.select {
|
330
|
+
.select { _1.is_a?(::REXML::Text) }
|
329
331
|
.uniq(&:object_id)
|
330
332
|
text_children.map(&:value).join
|
331
333
|
end
|
@@ -380,6 +382,8 @@ module Moxml
|
|
380
382
|
end
|
381
383
|
end
|
382
384
|
|
385
|
+
# not used at the moment
|
386
|
+
# but may be useful when the xpath is upgraded to work with namespaces
|
383
387
|
def prepare_xpath_namespaces(node)
|
384
388
|
ns = {}
|
385
389
|
|
@@ -430,10 +434,10 @@ module Moxml
|
|
430
434
|
|
431
435
|
# Write processing instructions
|
432
436
|
node.children.each do |child|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
+
next unless [::REXML::Instruction, ::REXML::CData, ::REXML::Comment, ::REXML::Text].include?(child.class)
|
438
|
+
|
439
|
+
write_with_formatter(child, output, options[:indent] || 2)
|
440
|
+
# output << "\n"
|
437
441
|
end
|
438
442
|
|
439
443
|
write_with_formatter(node.root, output, options[:indent] || 2) if node.root
|
data/lib/moxml/adapter.rb
CHANGED
data/lib/moxml/cdata.rb
CHANGED
data/lib/moxml/comment.rb
CHANGED
data/lib/moxml/context.rb
CHANGED
@@ -8,8 +8,8 @@ module Moxml
|
|
8
8
|
@config = Config.new(adapter)
|
9
9
|
end
|
10
10
|
|
11
|
-
def create_document
|
12
|
-
Document.new(config.adapter.create_document, self)
|
11
|
+
def create_document(native_doc = nil)
|
12
|
+
Document.new(config.adapter.create_document(native_doc), self)
|
13
13
|
end
|
14
14
|
|
15
15
|
def parse(xml, options = {})
|
data/lib/moxml/doctype.rb
CHANGED
data/lib/moxml/document.rb
CHANGED
@@ -63,7 +63,7 @@ module Moxml
|
|
63
63
|
if children.empty?
|
64
64
|
adapter.add_child(@native, node.native)
|
65
65
|
else
|
66
|
-
adapter.add_previous_sibling(children.first
|
66
|
+
adapter.add_previous_sibling(adapter.children(@native).first, node.native)
|
67
67
|
end
|
68
68
|
elsif root && !node.is_a?(ProcessingInstruction) && !node.is_a?(Comment)
|
69
69
|
raise Error, "Document already has a root element"
|
data/lib/moxml/element.rb
CHANGED
@@ -52,7 +52,8 @@ module Moxml
|
|
52
52
|
ns && Namespace.new(ns, context)
|
53
53
|
end
|
54
54
|
|
55
|
-
#
|
55
|
+
# add the prefix to the element name
|
56
|
+
# and add the namespace to the list of namespace definitions
|
56
57
|
def namespace=(ns_or_hash)
|
57
58
|
if ns_or_hash.is_a?(Hash)
|
58
59
|
adapter.set_namespace(
|
data/lib/moxml/namespace.rb
CHANGED
data/lib/moxml/node.rb
CHANGED
@@ -7,11 +7,17 @@ module Moxml
|
|
7
7
|
class Node
|
8
8
|
include XmlUtils
|
9
9
|
|
10
|
+
TYPES = %i[
|
11
|
+
element text cdata comment processing_instruction document
|
12
|
+
declaration doctype namespace attribute unknown
|
13
|
+
].freeze
|
14
|
+
|
10
15
|
attr_reader :native, :context
|
11
16
|
|
12
17
|
def initialize(native, context)
|
13
|
-
@native = native
|
14
18
|
@context = context
|
19
|
+
# @native = adapter.patch_node(native)
|
20
|
+
@native = native
|
15
21
|
end
|
16
22
|
|
17
23
|
def document
|
@@ -23,7 +29,10 @@ module Moxml
|
|
23
29
|
end
|
24
30
|
|
25
31
|
def children
|
26
|
-
NodeSet.new(
|
32
|
+
NodeSet.new(
|
33
|
+
adapter.children(@native).map { adapter.patch_node(_1, @native) },
|
34
|
+
context
|
35
|
+
)
|
27
36
|
end
|
28
37
|
|
29
38
|
def next_sibling
|
@@ -79,6 +88,12 @@ module Moxml
|
|
79
88
|
self.class == other.class && @native == other.native
|
80
89
|
end
|
81
90
|
|
91
|
+
TYPES.each do |node_type|
|
92
|
+
define_method "#{node_type}?" do
|
93
|
+
adapter.node_type(native) == node_type
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
82
97
|
def self.wrap(node, context)
|
83
98
|
return nil if node.nil?
|
84
99
|
|