moxml 0.1.22 → 0.1.24
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 +1 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +680 -110
- data/Rakefile +12 -9
- data/lib/compat/opal/moxml_boot.rb +53 -0
- data/lib/compat/opal/rexml/namespace.rb +8 -5
- data/lib/compat/opal/rexml/parsers/baseparser.rb +276 -212
- data/lib/compat/opal/rexml/source.rb +28 -27
- data/lib/compat/opal/rexml/text.rb +112 -104
- data/lib/compat/opal/rexml/xmltokens.rb +8 -8
- data/lib/compat/opal/rexml_compat.rb +12 -11
- data/lib/moxml/adapter/base.rb +5 -5
- data/lib/moxml/adapter/customized_libxml/cdata.rb +0 -2
- data/lib/moxml/adapter/customized_libxml/comment.rb +0 -2
- data/lib/moxml/adapter/customized_libxml/element.rb +3 -5
- data/lib/moxml/adapter/customized_libxml/node.rb +2 -2
- data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +0 -2
- data/lib/moxml/adapter/customized_libxml/text.rb +0 -2
- data/lib/moxml/adapter/customized_oga/xml_declaration.rb +8 -1
- data/lib/moxml/adapter/customized_rexml/formatter.rb +7 -8
- data/lib/moxml/adapter/headed_ox.rb +1 -5
- data/lib/moxml/adapter/libxml/entity_ref_registry.rb +4 -2
- data/lib/moxml/adapter/libxml/entity_restorer.rb +3 -1
- data/lib/moxml/adapter/libxml.rb +29 -14
- data/lib/moxml/adapter/nokogiri.rb +21 -17
- data/lib/moxml/adapter/oga.rb +48 -67
- data/lib/moxml/adapter/ox.rb +61 -31
- data/lib/moxml/adapter/rexml.rb +5 -6
- data/lib/moxml/adapter.rb +13 -5
- data/lib/moxml/attribute.rb +5 -2
- data/lib/moxml/config.rb +16 -2
- data/lib/moxml/context.rb +8 -8
- data/lib/moxml/declaration.rb +2 -7
- data/lib/moxml/document.rb +2 -19
- data/lib/moxml/document_builder.rb +12 -8
- data/lib/moxml/element.rb +4 -4
- data/lib/moxml/entity_registry.rb +8 -4
- data/lib/moxml/entity_registry_opal_data.rb +3 -2
- data/lib/moxml/node.rb +45 -14
- data/lib/moxml/node_set.rb +2 -4
- data/lib/moxml/sax/block_handler.rb +0 -2
- data/lib/moxml/sax/element_handler.rb +0 -2
- data/lib/moxml/sax/namespace_splitter.rb +5 -4
- data/lib/moxml/sax.rb +4 -25
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xml_utils.rb +2 -3
- data/lib/moxml/xpath/compiler.rb +1 -49
- data/lib/moxml/xpath/conversion.rb +7 -6
- data/lib/moxml/xpath/ruby/generator.rb +12 -19
- data/lib/moxml/xpath/ruby/node.rb +1 -9
- data/lib/moxml/xpath.rb +6 -14
- data/lib/moxml.rb +74 -20
- data/spec/integration/all_adapters_spec.rb +1 -0
- data/spec/integration/shared_examples/line_ending_behavior.rb +56 -0
- data/spec/moxml/adapter/libxml_internals_spec.rb +4 -2
- data/spec/moxml/adapter/platform_spec.rb +2 -1
- data/spec/moxml/attribute_spec.rb +16 -0
- data/spec/moxml/config_spec.rb +33 -0
- data/spec/moxml/context_spec.rb +14 -0
- data/spec/moxml/moxml_spec.rb +13 -0
- data/spec/moxml/node_spec.rb +58 -0
- data/spec/moxml/xpath/ruby/node_spec.rb +3 -3
- metadata +4 -2
data/lib/moxml/adapter/base.rb
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../xml_utils"
|
|
4
|
-
require_relative "../document_builder"
|
|
5
|
-
|
|
6
3
|
module Moxml
|
|
7
4
|
module Adapter
|
|
8
5
|
class Base
|
|
@@ -104,8 +101,7 @@ module Moxml
|
|
|
104
101
|
#
|
|
105
102
|
# @return [Boolean] true if SAX parsing is supported
|
|
106
103
|
def sax_supported?
|
|
107
|
-
|
|
108
|
-
method(:sax_parse).owner != Moxml::Adapter::Base.singleton_class
|
|
104
|
+
method(:sax_parse).owner != Moxml::Adapter::Base.singleton_class
|
|
109
105
|
end
|
|
110
106
|
|
|
111
107
|
def create_document(_native_doc = nil)
|
|
@@ -212,6 +208,10 @@ namespace_validation_mode: :strict)
|
|
|
212
208
|
wrapper.has_xml_declaration
|
|
213
209
|
end
|
|
214
210
|
|
|
211
|
+
# Clear the declaration state from the native document.
|
|
212
|
+
# Called when a Declaration node is removed from a document.
|
|
213
|
+
def remove_declaration(_native_doc); end
|
|
214
|
+
|
|
215
215
|
# Return the actual native node after an add_child operation.
|
|
216
216
|
# Override for adapters where node identity may change (e.g., LibXML doc.root=).
|
|
217
217
|
def actual_native(child_native, _parent_native)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "node"
|
|
4
|
-
|
|
5
3
|
module Moxml
|
|
6
4
|
module Adapter
|
|
7
5
|
module CustomizedLibxml
|
|
@@ -12,7 +10,7 @@ module Moxml
|
|
|
12
10
|
class Element < Node
|
|
13
11
|
# Add a child to this element, handling document import automatically
|
|
14
12
|
def add_child(child)
|
|
15
|
-
child_native = child.
|
|
13
|
+
child_native = child.is_a?(Node) ? child.native : child
|
|
16
14
|
|
|
17
15
|
# Check if child needs to be imported
|
|
18
16
|
if needs_import?(child_native)
|
|
@@ -26,9 +24,9 @@ module Moxml
|
|
|
26
24
|
private
|
|
27
25
|
|
|
28
26
|
def needs_import?(child_node)
|
|
29
|
-
return false unless @native.
|
|
27
|
+
return false unless @native.is_a?(::LibXML::XML::Node)
|
|
30
28
|
return false unless @native.doc
|
|
31
|
-
return false unless child_node.
|
|
29
|
+
return false unless child_node.is_a?(::LibXML::XML::Node)
|
|
32
30
|
return false unless child_node.doc
|
|
33
31
|
|
|
34
32
|
child_node.doc != @native.doc
|
|
@@ -22,7 +22,7 @@ module Moxml
|
|
|
22
22
|
def ==(other)
|
|
23
23
|
return false unless other
|
|
24
24
|
|
|
25
|
-
other_native = other.
|
|
25
|
+
other_native = other.is_a?(self.class) ? other.native : other
|
|
26
26
|
@native == other_native
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -34,7 +34,7 @@ module Moxml
|
|
|
34
34
|
|
|
35
35
|
# Check if node has a document
|
|
36
36
|
def document_present?
|
|
37
|
-
@native.
|
|
37
|
+
@native.is_a?(::LibXML::XML::Node) && !@native.doc.nil?
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
# Get the document this node belongs to
|
|
@@ -8,10 +8,17 @@ module Moxml
|
|
|
8
8
|
class XmlDeclaration < ::Oga::XML::XmlDeclaration
|
|
9
9
|
def initialize(options = {})
|
|
10
10
|
@version = options[:version] || "1.0"
|
|
11
|
-
# encoding is optional, but Oga sets it to UTF-8 by default
|
|
12
11
|
@encoding = options[:encoding]
|
|
13
12
|
@standalone = options[:standalone]
|
|
14
13
|
end
|
|
14
|
+
|
|
15
|
+
def to_xml
|
|
16
|
+
parts = ["<?xml"]
|
|
17
|
+
parts << %( version="#{version}") if version
|
|
18
|
+
parts << %( encoding="#{encoding}") if encoding
|
|
19
|
+
parts << %( standalone="#{standalone}") if standalone
|
|
20
|
+
"#{parts.join}?>"
|
|
21
|
+
end
|
|
15
22
|
end
|
|
16
23
|
end
|
|
17
24
|
end
|
|
@@ -70,12 +70,12 @@ module Moxml
|
|
|
70
70
|
child.to_s.strip.empty? &&
|
|
71
71
|
!(child.next_sibling.nil? && child.previous_sibling.nil?)
|
|
72
72
|
|
|
73
|
-
output << "\n" << (
|
|
73
|
+
output << "\n" << (" " * @level) if indent_children
|
|
74
74
|
write(child, output)
|
|
75
75
|
end
|
|
76
76
|
when :eref
|
|
77
77
|
if eref_idx < entity_refs.size
|
|
78
|
-
output << "\n" << (
|
|
78
|
+
output << "\n" << (" " * @level) if indent_children
|
|
79
79
|
write(entity_refs[eref_idx], output)
|
|
80
80
|
eref_idx += 1
|
|
81
81
|
end
|
|
@@ -87,14 +87,14 @@ module Moxml
|
|
|
87
87
|
child.to_s.strip.empty? &&
|
|
88
88
|
!(child.next_sibling.nil? && child.previous_sibling.nil?)
|
|
89
89
|
|
|
90
|
-
output << "\n" << (
|
|
90
|
+
output << "\n" << (" " * @level) if indent_children
|
|
91
91
|
write(child, output)
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
if indent_children
|
|
96
96
|
@level -= @indentation.length
|
|
97
|
-
output << "\n" << (
|
|
97
|
+
output << "\n" << (" " * @level)
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
100
|
|
|
@@ -185,9 +185,8 @@ module Moxml
|
|
|
185
185
|
node.attributes.each do |name, attr|
|
|
186
186
|
next unless name.to_s.start_with?("xmlns:") || name.to_s == "xmlns"
|
|
187
187
|
|
|
188
|
-
# convert the default namespace
|
|
189
188
|
name = "xmlns" if name.to_s == "xmlns:"
|
|
190
|
-
value = attr.
|
|
189
|
+
value = attr.is_a?(::REXML::Attribute) ? attr.value : attr
|
|
191
190
|
output << " #{name}=\"#{value}\""
|
|
192
191
|
end
|
|
193
192
|
|
|
@@ -196,14 +195,14 @@ module Moxml
|
|
|
196
195
|
next if name.to_s.start_with?("xmlns:") || name.to_s == "xmlns"
|
|
197
196
|
|
|
198
197
|
output << " "
|
|
199
|
-
output << if attr.
|
|
198
|
+
output << if attr.is_a?(::REXML::Attribute) && attr.prefix
|
|
200
199
|
"#{attr.prefix}:#{attr.name}"
|
|
201
200
|
else
|
|
202
201
|
name.to_s
|
|
203
202
|
end
|
|
204
203
|
|
|
205
204
|
output << "=\""
|
|
206
|
-
value = attr.
|
|
205
|
+
value = attr.is_a?(::REXML::Attribute) ? attr.value : attr
|
|
207
206
|
output << escape_attribute_value(value.to_s)
|
|
208
207
|
output << "\""
|
|
209
208
|
end # rubocop:enable Style/CombinableLoops
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
return if RUBY_ENGINE == "opal"
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
require_relative "../xpath"
|
|
7
|
-
# Force load XPath modules (autoload doesn't work well with relative requires in examples)
|
|
8
|
-
require_relative "../xpath/parser"
|
|
9
|
-
require_relative "../xpath/compiler"
|
|
5
|
+
require "moxml/adapter/ox"
|
|
10
6
|
|
|
11
7
|
module Moxml
|
|
12
8
|
module Adapter
|
|
@@ -9,7 +9,8 @@ module Moxml
|
|
|
9
9
|
ENTITY_REFS_KEY = :_entity_ref_pairs
|
|
10
10
|
CHILD_SEQUENCE_KEY = :_child_seq_pairs
|
|
11
11
|
NON_WHITESPACE_RE = /\S/
|
|
12
|
-
private_constant :ENTITY_REFS_KEY, :CHILD_SEQUENCE_KEY,
|
|
12
|
+
private_constant :ENTITY_REFS_KEY, :CHILD_SEQUENCE_KEY,
|
|
13
|
+
:NON_WHITESPACE_RE
|
|
13
14
|
|
|
14
15
|
def initialize(attachments, doc)
|
|
15
16
|
@attachments = attachments
|
|
@@ -34,7 +35,8 @@ module Moxml
|
|
|
34
35
|
if existing
|
|
35
36
|
existing << :eref
|
|
36
37
|
else
|
|
37
|
-
seq_by_path[path] =
|
|
38
|
+
seq_by_path[path] =
|
|
39
|
+
Array.new(count_native_children(element), :native)
|
|
38
40
|
seq_by_path[path] << :eref
|
|
39
41
|
@attachments.set(@doc, CHILD_SEQUENCE_KEY, seq_by_path)
|
|
40
42
|
end
|
|
@@ -76,7 +76,9 @@ module Moxml
|
|
|
76
76
|
def append_chunk(parent, type, payload)
|
|
77
77
|
case type
|
|
78
78
|
when :text
|
|
79
|
-
parent.add_child(::Moxml::Text.new(
|
|
79
|
+
parent.add_child(::Moxml::Text.new(
|
|
80
|
+
@adapter.create_native_text(payload), @ctx
|
|
81
|
+
))
|
|
80
82
|
when :eref
|
|
81
83
|
parent.add_child(
|
|
82
84
|
::Moxml::EntityReference.new(
|
data/lib/moxml/adapter/libxml.rb
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
return if RUBY_ENGINE == "opal"
|
|
4
4
|
|
|
5
|
-
require_relative "base"
|
|
6
5
|
require "libxml"
|
|
7
|
-
require_relative "customized_libxml"
|
|
8
|
-
require_relative "../sax/namespace_splitter"
|
|
9
6
|
|
|
10
7
|
module Moxml
|
|
11
8
|
module Adapter
|
|
12
9
|
class Libxml < Base
|
|
10
|
+
autoload :EntityRefRegistry, "moxml/adapter/libxml/entity_ref_registry"
|
|
11
|
+
autoload :EntityRestorer, "moxml/adapter/libxml/entity_restorer"
|
|
12
|
+
|
|
13
13
|
# Wrapper class to store DOCTYPE information
|
|
14
14
|
class DoctypeWrapper
|
|
15
15
|
attr_reader :native_doc
|
|
@@ -239,7 +239,7 @@ module Moxml
|
|
|
239
239
|
# Duck-typed fallback for libxml types that aren't ::Node
|
|
240
240
|
# subclasses but still expose node_type (e.g. ::Attr).
|
|
241
241
|
native = unpatch_node(node)
|
|
242
|
-
return :unknown unless native.
|
|
242
|
+
return :unknown unless native.is_a?(::LibXML::XML::Node)
|
|
243
243
|
|
|
244
244
|
NATIVE_NODE_TYPE_MAP[native.node_type] || :unknown
|
|
245
245
|
end
|
|
@@ -836,7 +836,7 @@ module Moxml
|
|
|
836
836
|
return [] unless namespaces
|
|
837
837
|
|
|
838
838
|
namespace_list =
|
|
839
|
-
if namespaces.
|
|
839
|
+
if namespaces.is_a?(::LibXML::XML::Namespaces)
|
|
840
840
|
namespaces.definitions
|
|
841
841
|
else
|
|
842
842
|
namespaces
|
|
@@ -1076,6 +1076,11 @@ module Moxml
|
|
|
1076
1076
|
end
|
|
1077
1077
|
end
|
|
1078
1078
|
|
|
1079
|
+
def remove_declaration(native_doc)
|
|
1080
|
+
decl = attachments.get(native_doc, :declaration)
|
|
1081
|
+
decl&.removed = true
|
|
1082
|
+
end
|
|
1083
|
+
|
|
1079
1084
|
# LibXML's doc.root= creates a new Ruby wrapper with different object_id.
|
|
1080
1085
|
# Return the actual root node so attachments are stored on the correct object.
|
|
1081
1086
|
def actual_native(child_native, parent_native)
|
|
@@ -1182,7 +1187,8 @@ module Moxml
|
|
|
1182
1187
|
end
|
|
1183
1188
|
|
|
1184
1189
|
ESCAPE_XML_RE = /[&<>"]/
|
|
1185
|
-
ESCAPE_XML_MAP = { "&" => "&", "<" => "<", ">" => ">",
|
|
1190
|
+
ESCAPE_XML_MAP = { "&" => "&", "<" => "<", ">" => ">",
|
|
1191
|
+
'"' => """ }.freeze
|
|
1186
1192
|
private_constant :ESCAPE_XML_RE, :ESCAPE_XML_MAP
|
|
1187
1193
|
|
|
1188
1194
|
def escape_xml(text)
|
|
@@ -1278,7 +1284,13 @@ module Moxml
|
|
|
1278
1284
|
# attachment query that otherwise fires for every element under
|
|
1279
1285
|
# Monitor#synchronize.
|
|
1280
1286
|
eref_active = doc_eref_active?(elem.doc) if eref_active.nil?
|
|
1281
|
-
entity_refs, child_sequence = eref_active
|
|
1287
|
+
entity_refs, child_sequence = if eref_active
|
|
1288
|
+
lookup_entity_ref_serialization(elem)
|
|
1289
|
+
else
|
|
1290
|
+
[
|
|
1291
|
+
nil, nil
|
|
1292
|
+
]
|
|
1293
|
+
end
|
|
1282
1294
|
|
|
1283
1295
|
# Always use verbose format <tag></tag> for consistency with other adapters
|
|
1284
1296
|
output << ">"
|
|
@@ -1312,7 +1324,7 @@ module Moxml
|
|
|
1312
1324
|
return unless elem.is_a?(::LibXML::XML::Node)
|
|
1313
1325
|
|
|
1314
1326
|
ns_list = elem.namespaces
|
|
1315
|
-
return unless ns_list.
|
|
1327
|
+
return unless ns_list.is_a?(::LibXML::XML::Namespaces)
|
|
1316
1328
|
|
|
1317
1329
|
definitions = ns_list.definitions
|
|
1318
1330
|
return if definitions.empty?
|
|
@@ -1544,7 +1556,7 @@ module Moxml
|
|
|
1544
1556
|
|
|
1545
1557
|
# Also check if this element has an active namespace (inherited or own)
|
|
1546
1558
|
# This catches cases where elements inherit namespaces from parents
|
|
1547
|
-
if node.is_a?(::LibXML::XML::Node) && node.namespaces.
|
|
1559
|
+
if node.is_a?(::LibXML::XML::Node) && node.namespaces.is_a?(::LibXML::XML::Namespaces)
|
|
1548
1560
|
active_ns = node.namespaces.namespace
|
|
1549
1561
|
if active_ns
|
|
1550
1562
|
prefix = active_ns.prefix
|
|
@@ -1622,8 +1634,14 @@ module Moxml
|
|
|
1622
1634
|
# duplicated — callers that need the subtree use deep_duplicate_node.
|
|
1623
1635
|
def shallow_duplicate_element(native_node)
|
|
1624
1636
|
new_node = ::LibXML::XML::Node.new(native_node.name)
|
|
1625
|
-
|
|
1626
|
-
|
|
1637
|
+
if native_node.is_a?(::LibXML::XML::Node)
|
|
1638
|
+
copy_element_namespaces(native_node,
|
|
1639
|
+
new_node)
|
|
1640
|
+
end
|
|
1641
|
+
if native_node.attributes?
|
|
1642
|
+
copy_element_attributes(native_node,
|
|
1643
|
+
new_node)
|
|
1644
|
+
end
|
|
1627
1645
|
new_node
|
|
1628
1646
|
end
|
|
1629
1647
|
|
|
@@ -1707,6 +1725,3 @@ module Moxml
|
|
|
1707
1725
|
end
|
|
1708
1726
|
end
|
|
1709
1727
|
end
|
|
1710
|
-
|
|
1711
|
-
require_relative "libxml/entity_ref_registry"
|
|
1712
|
-
require_relative "libxml/entity_restorer"
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
return if RUBY_ENGINE == "opal"
|
|
4
4
|
|
|
5
|
-
require_relative "base"
|
|
6
5
|
require "nokogiri"
|
|
7
|
-
require_relative "../sax/namespace_splitter"
|
|
8
6
|
|
|
9
7
|
module Moxml
|
|
10
8
|
module Adapter
|
|
@@ -245,25 +243,22 @@ module Moxml
|
|
|
245
243
|
end
|
|
246
244
|
|
|
247
245
|
def add_child(element, child)
|
|
248
|
-
# Special handling for declarations on Nokogiri documents
|
|
249
246
|
if element.is_a?(::Nokogiri::XML::Document) &&
|
|
250
247
|
child.is_a?(::Nokogiri::XML::ProcessingInstruction) &&
|
|
251
248
|
child.name == "xml"
|
|
252
|
-
# Set document's xml_decl property
|
|
253
249
|
version = declaration_attribute(child, "version") || "1.0"
|
|
254
250
|
encoding = declaration_attribute(child, "encoding")
|
|
255
251
|
standalone = declaration_attribute(child, "standalone")
|
|
256
252
|
|
|
257
|
-
# Store declaration state in attachment map
|
|
258
253
|
attachments.set(element, :xml_decl, {
|
|
259
254
|
version: version,
|
|
260
255
|
encoding: encoding,
|
|
261
256
|
standalone: standalone,
|
|
262
257
|
}.compact)
|
|
258
|
+
return
|
|
263
259
|
end
|
|
264
260
|
|
|
265
261
|
if node_type(child) == :doctype
|
|
266
|
-
# avoid exceptions: cannot reparent Nokogiri::XML::DTD there
|
|
267
262
|
element.create_internal_subset(
|
|
268
263
|
child.name, child.external_id, child.system_id
|
|
269
264
|
)
|
|
@@ -397,23 +392,28 @@ module Moxml
|
|
|
397
392
|
save_options |= ::Nokogiri::XML::Node::SaveOptions::FORMAT
|
|
398
393
|
end
|
|
399
394
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
save_options |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION if xml_decl.nil?
|
|
395
|
+
custom_decl = nil
|
|
396
|
+
if options[:no_declaration]
|
|
397
|
+
save_options |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
|
398
|
+
elsif attachments.key?(node, :xml_decl) && (xml_decl = attachments.get(node, :xml_decl))
|
|
399
|
+
save_options |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
|
|
400
|
+
attrs = ["version=\"#{xml_decl[:version]}\""]
|
|
401
|
+
attrs << "encoding=\"#{xml_decl[:encoding]}\"" if xml_decl[:encoding]
|
|
402
|
+
attrs << "standalone=\"#{xml_decl[:standalone]}\"" if xml_decl[:standalone]
|
|
403
|
+
custom_decl = "<?xml #{attrs.join(' ')}?>"
|
|
410
404
|
end
|
|
411
405
|
|
|
412
|
-
node.to_xml(
|
|
406
|
+
result = node.to_xml(
|
|
413
407
|
indent: options[:indent],
|
|
414
408
|
encoding: options[:encoding],
|
|
415
409
|
save_with: save_options,
|
|
416
410
|
)
|
|
411
|
+
|
|
412
|
+
if custom_decl
|
|
413
|
+
result = "#{custom_decl}\n#{result}"
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
result
|
|
417
417
|
end
|
|
418
418
|
|
|
419
419
|
def has_declaration?(native_doc, wrapper)
|
|
@@ -424,6 +424,10 @@ module Moxml
|
|
|
424
424
|
end
|
|
425
425
|
end
|
|
426
426
|
|
|
427
|
+
def remove_declaration(native_doc)
|
|
428
|
+
attachments.set(native_doc, :xml_decl, nil)
|
|
429
|
+
end
|
|
430
|
+
|
|
427
431
|
private
|
|
428
432
|
|
|
429
433
|
def build_declaration_attrs(version, encoding, standalone)
|
data/lib/moxml/adapter/oga.rb
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "base"
|
|
4
|
-
require_relative "customized_oga"
|
|
5
3
|
require "oga"
|
|
6
|
-
require_relative "../sax/namespace_splitter"
|
|
7
4
|
|
|
8
5
|
module Moxml
|
|
9
6
|
module Adapter
|
|
@@ -289,11 +286,25 @@ module Moxml
|
|
|
289
286
|
child_or_text
|
|
290
287
|
end
|
|
291
288
|
|
|
292
|
-
# Special handling for declarations on Oga documents
|
|
293
289
|
if element.is_a?(::Oga::XML::Document) &&
|
|
294
290
|
child.is_a?(::Oga::XML::XmlDeclaration)
|
|
295
|
-
# Track declaration state in attachment map
|
|
296
291
|
attachments.set(element, :xml_declaration, child)
|
|
292
|
+
return
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Insert doctype before root element in document
|
|
296
|
+
if element.is_a?(::Oga::XML::Document) && child.is_a?(::Oga::XML::Doctype)
|
|
297
|
+
root_idx = nil
|
|
298
|
+
element.children.each_with_index do |n, i|
|
|
299
|
+
if n.is_a?(::Oga::XML::Element)
|
|
300
|
+
root_idx = i
|
|
301
|
+
break
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
if root_idx
|
|
305
|
+
element.children.insert(root_idx, child)
|
|
306
|
+
return
|
|
307
|
+
end
|
|
297
308
|
end
|
|
298
309
|
|
|
299
310
|
element.children << child
|
|
@@ -456,95 +467,65 @@ module Moxml
|
|
|
456
467
|
def has_declaration?(native_doc, _wrapper)
|
|
457
468
|
decl = attachments.get(native_doc, :xml_declaration)
|
|
458
469
|
if decl.nil? && !attachments.key?(native_doc, :xml_declaration)
|
|
459
|
-
|
|
460
|
-
native_doc.respond_to?(:xml_declaration) && !native_doc.xml_declaration.nil?
|
|
470
|
+
native_doc.is_a?(::Oga::XML::Document) && !native_doc.xml_declaration.nil?
|
|
461
471
|
else
|
|
462
472
|
!decl.nil?
|
|
463
473
|
end
|
|
464
474
|
end
|
|
465
475
|
|
|
476
|
+
def remove_declaration(native_doc)
|
|
477
|
+
attachments.set(native_doc, :xml_declaration, nil)
|
|
478
|
+
end
|
|
479
|
+
|
|
466
480
|
private
|
|
467
481
|
|
|
482
|
+
def declaration_to_xml(decl)
|
|
483
|
+
parts = ["<?xml"]
|
|
484
|
+
parts << %( version="#{decl.version}") if decl.version
|
|
485
|
+
parts << %( encoding="#{decl.encoding}") if decl.encoding
|
|
486
|
+
parts << %( standalone="#{decl.standalone}") if decl.standalone
|
|
487
|
+
"#{parts.join}?>"
|
|
488
|
+
end
|
|
489
|
+
|
|
468
490
|
def serialize_without_entity_processing(node, options = {})
|
|
469
|
-
# Oga's XmlGenerator doesn't support options directly
|
|
470
|
-
# We need to handle declaration options ourselves for Document nodes
|
|
471
491
|
if node.is_a?(::Oga::XML::Document)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
effective_xml_declaration = node.xml_declaration || attachments.get(
|
|
475
|
-
node, :xml_declaration
|
|
476
|
-
)
|
|
492
|
+
effective_xml_declaration = attachments.get(node, :xml_declaration)
|
|
493
|
+
|
|
477
494
|
should_include_decl = if options.key?(:no_declaration)
|
|
478
495
|
!options[:no_declaration]
|
|
479
496
|
elsif options.key?(:declaration)
|
|
480
497
|
options[:declaration]
|
|
481
498
|
else
|
|
482
|
-
|
|
483
|
-
effective_xml_declaration ? true : false
|
|
499
|
+
effective_xml_declaration || node.xml_declaration ? true : false
|
|
484
500
|
end
|
|
485
501
|
|
|
486
|
-
|
|
487
|
-
# This prevents duplicate declarations when document already has one
|
|
488
|
-
has_existing_declaration = node.children.any?(::Oga::XML::XmlDeclaration)
|
|
502
|
+
output = []
|
|
489
503
|
|
|
490
|
-
if should_include_decl
|
|
491
|
-
|
|
492
|
-
output
|
|
493
|
-
|
|
504
|
+
if should_include_decl
|
|
505
|
+
decl = effective_xml_declaration || node.xml_declaration
|
|
506
|
+
output << if decl
|
|
507
|
+
declaration_to_xml(decl)
|
|
508
|
+
else
|
|
509
|
+
'<?xml version="1.0" encoding="UTF-8"?>'
|
|
510
|
+
end
|
|
494
511
|
output << "\n"
|
|
495
|
-
|
|
496
|
-
# Serialize doctype if present
|
|
497
|
-
output << node.doctype.to_xml << "\n" if node.doctype
|
|
498
|
-
|
|
499
|
-
# Serialize children
|
|
500
|
-
node.children.each do |child|
|
|
501
|
-
output << ::Moxml::Adapter::CustomizedOga::XmlGenerator.new(child).to_xml
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
return output.join
|
|
505
|
-
elsif !should_include_decl
|
|
506
|
-
# Skip xml_declaration
|
|
507
|
-
output = []
|
|
508
|
-
|
|
509
|
-
# Serialize doctype if present
|
|
510
|
-
output << node.doctype.to_xml << "\n" if node.doctype
|
|
511
|
-
|
|
512
|
-
# Serialize root and other children
|
|
513
|
-
node.children.each do |child|
|
|
514
|
-
next if child.is_a?(::Oga::XML::XmlDeclaration)
|
|
515
|
-
|
|
516
|
-
output << ::Moxml::Adapter::CustomizedOga::XmlGenerator.new(child).to_xml
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
return output.join
|
|
520
512
|
end
|
|
521
|
-
end
|
|
522
513
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
))
|
|
528
|
-
if node.is_a?(::Oga::XML::Document) && effective_xml_declaration
|
|
529
|
-
# Document has declaration - use custom handling to avoid duplicates
|
|
530
|
-
output = []
|
|
531
|
-
xml_declaration_serialized = false
|
|
514
|
+
if node.doctype
|
|
515
|
+
output << node.doctype.to_xml
|
|
516
|
+
output << "\n"
|
|
517
|
+
end
|
|
532
518
|
|
|
533
|
-
# Serialize children, but skip XmlDeclaration if it would cause duplication
|
|
534
519
|
node.children.each do |child|
|
|
535
|
-
|
|
536
|
-
next if xml_declaration && xml_declaration_serialized
|
|
537
|
-
|
|
538
|
-
xml_declaration_serialized = true if xml_declaration
|
|
520
|
+
next if child.is_a?(::Oga::XML::XmlDeclaration)
|
|
539
521
|
|
|
540
522
|
output << ::Moxml::Adapter::CustomizedOga::XmlGenerator.new(child).to_xml
|
|
541
523
|
end
|
|
542
524
|
|
|
543
|
-
output.join
|
|
544
|
-
else
|
|
545
|
-
# Normal case - use XmlGenerator directly
|
|
546
|
-
::Moxml::Adapter::CustomizedOga::XmlGenerator.new(node).to_xml
|
|
525
|
+
return output.join
|
|
547
526
|
end
|
|
527
|
+
|
|
528
|
+
::Moxml::Adapter::CustomizedOga::XmlGenerator.new(node).to_xml
|
|
548
529
|
end
|
|
549
530
|
end
|
|
550
531
|
end
|