Class: Moxml::Adapter::Base

Inherits:
Object
  • Object
show all
Extended by:
XmlUtils
Defined in:
lib/moxml/adapter/base.rb

Direct Known Subclasses

Leptris, Libxml, Nokogiri, Oga, Ox, Rexml

Class Method Summary collapse

Methods included from XmlUtils

encode_entities, normalize_xml_value, validate_comment_content, validate_declaration_encoding, validate_declaration_standalone, validate_declaration_version, validate_element_name, validate_entity_reference_name, validate_pi_target, validate_prefix, validate_uri

Class Method Details

.actual_native(child_native, _parent_native) ⇒ Object

Return the actual native node after an add_child operation. Override for adapters where node identity may change (e.g., LibXML doc.root=).



229
230
231
# File 'lib/moxml/adapter/base.rb', line 229

def actual_native(child_native, _parent_native)
  child_native
end

.attribute_name(attr) ⇒ Object

Local name of a native attribute node. Adapters whose natives carry qualified names override this to expose the local part; the wrapper composes the prefix.



223
224
225
# File 'lib/moxml/adapter/base.rb', line 223

def attribute_name(attr)
  attr.name
end

.bulk_materialize?Boolean

Whether the engine offers a bulk materialization path for Materializer (issue #132). When true, materialize_records yields flattened records for the subtree; returning nil (e.g. for document shapes the bulk path cannot express) falls back to the generic wrapper walk.

Returns:

  • (Boolean)


197
198
199
# File 'lib/moxml/adapter/base.rb', line 197

def bulk_materialize?
  false
end

.create_cdata(content, owner_doc: nil) ⇒ Object



82
83
84
# File 'lib/moxml/adapter/base.rb', line 82

def create_cdata(content, owner_doc: nil)
  create_native_cdata(normalize_xml_value(content), owner_doc)
end

.create_comment(content, owner_doc: nil) ⇒ Object



86
87
88
89
# File 'lib/moxml/adapter/base.rb', line 86

def create_comment(content, owner_doc: nil)
  validate_comment_content(content)
  create_native_comment(normalize_xml_value(content), owner_doc)
end

.create_declaration(version = "1.0", encoding = "UTF-8", standalone = nil) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/moxml/adapter/base.rb', line 101

def create_declaration(version = "1.0", encoding = "UTF-8",
                       standalone = nil)
  validate_declaration_version(version)
  validate_declaration_encoding(encoding)
  validate_declaration_standalone(standalone)
  create_native_declaration(version, encoding, standalone)
end

.create_doctype(name, external_id, system_id) ⇒ Object



91
92
93
# File 'lib/moxml/adapter/base.rb', line 91

def create_doctype(name, external_id, system_id)
  create_native_doctype(name, external_id, system_id)
end

.create_document(_native_doc = nil) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/moxml/adapter/base.rb', line 64

def create_document(_native_doc = nil)
  raise Moxml::NotImplementedError.new(
    "create_document not implemented",
    feature: "create_document",
    adapter: name,
  )
end

.create_element(name, owner_doc: nil) ⇒ Object



72
73
74
75
# File 'lib/moxml/adapter/base.rb', line 72

def create_element(name, owner_doc: nil)
  validate_element_name(name)
  create_native_element(name, owner_doc)
end

.create_entity_reference(name) ⇒ Object



127
128
129
130
# File 'lib/moxml/adapter/base.rb', line 127

def create_entity_reference(name)
  validate_entity_reference_name(name)
  create_native_entity_reference(name)
end

.create_namespace(element, prefix, uri, namespace_validation_mode: :strict) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/moxml/adapter/base.rb', line 109

def create_namespace(element, prefix, uri,
namespace_validation_mode: :strict)
  if prefix && uri.to_s.empty?
    raise NamespaceError.new(
      "Prefixed namespace declaration cannot have an empty URI",
      prefix: prefix,
      uri: uri,
    )
  end
  if namespace_validation_mode == :strict
    validate_prefix(prefix) if prefix
    validate_uri(uri, mode: :strict)
  else
    validate_uri(uri, mode: :lenient)
  end
  create_native_namespace(element, prefix, uri)
end

.create_processing_instruction(target, content) ⇒ Object



95
96
97
98
99
# File 'lib/moxml/adapter/base.rb', line 95

def create_processing_instruction(target, content)
  validate_pi_target(target)
  create_native_processing_instruction(target,
                                       normalize_xml_value(content))
end

.create_text(content, owner_doc: nil) ⇒ Object



77
78
79
80
# File 'lib/moxml/adapter/base.rb', line 77

def create_text(content, owner_doc: nil)
  # Ox freezes the content, so we need to dup it
  create_native_text(normalize_xml_value(content).dup, owner_doc)
end

.decode_entities(text) ⇒ Object



15
16
17
# File 'lib/moxml/adapter/base.rb', line 15

def decode_entities(text)
  Entity.decode_entities(text)
end

.duplicate_node(node) ⇒ Object



167
168
169
# File 'lib/moxml/adapter/base.rb', line 167

def duplicate_node(node)
  node.dup
end

.entity_bearing?(_native) ⇒ Boolean

Whether the subtree at native can contain entity markers. Marker-tracking adapters override this so the post-serialize restore can skip its full-output scans on marker-free documents; the default stays conservative.

Returns:

  • (Boolean)


188
189
190
# File 'lib/moxml/adapter/base.rb', line 188

def entity_bearing?(_native)
  true
end

.entity_reference_name(node) ⇒ Object



163
164
165
# File 'lib/moxml/adapter/base.rb', line 163

def entity_reference_name(node)
  node.name
end

.has_declaration?(_native_doc, wrapper) ⇒ Boolean

Check if the native document has an XML declaration

Parameters:

  • native_doc

    the native document object

  • wrapper (Moxml::Document)

    the wrapper with has_xml_declaration flag

Returns:

  • (Boolean)


205
206
207
# File 'lib/moxml/adapter/base.rb', line 205

def has_declaration?(_native_doc, wrapper)
  wrapper.has_xml_declaration
end

.in_scope_namespaces(element) ⇒ Object

Returns all namespaces in scope for this element, including inherited from ancestors. Adapters with native support (Nokogiri) override this. Default walks the ancestor chain.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/moxml/adapter/base.rb', line 246

def in_scope_namespaces(element)
  namespaces = {}
  node = element

  while node
    break unless node_type(node) == :element

    namespace_definitions(node).each do |ns|
      prefix = namespace_prefix(ns)
      namespaces[prefix] = ns unless namespaces.key?(prefix)
    end
    node = parent(node)
  end

  namespaces.values
end

.line_number(_node) ⇒ Object

Source line of a native node (1-based), or nil when the underlying backend does not track source positions. Adapters that track lines (Nokogiri, LibXML) override this.



216
217
218
# File 'lib/moxml/adapter/base.rb', line 216

def line_number(_node)
  nil
end

.parse(_xml, _options = {}, _context = nil) ⇒ Object



31
32
33
34
35
36
37
# File 'lib/moxml/adapter/base.rb', line 31

def parse(_xml, _options = {}, _context = nil)
  raise Moxml::NotImplementedError.new(
    "parse not implemented",
    feature: "parse",
    adapter: name,
  )
end

.patch_node(node, _parent = nil) ⇒ Object



171
172
173
174
# File 'lib/moxml/adapter/base.rb', line 171

def patch_node(node, _parent = nil)
  # monkey-patch the native node if necessary
  node
end

.patches_children?Boolean

Whether children() results need per-child patch_node rewriting. Adapters whose natives arrive pre-wrapped (all but ox and libxml) answer false so the wrapper layer can skip the identity map over every child list.

Returns:

  • (Boolean)


180
181
182
# File 'lib/moxml/adapter/base.rb', line 180

def patches_children?
  false
end

.preprocess_entities(xml) ⇒ Object



11
12
13
# File 'lib/moxml/adapter/base.rb', line 11

def preprocess_entities(xml)
  Entity.preprocess_entities(xml)
end

.remove_attribute_native(attr) ⇒ Object

Remove a specific native attribute node from its owning element. Semantics (which attribute a name addresses) live in Moxml::AttributeResolver; this is the raw primitive.



159
160
161
# File 'lib/moxml/adapter/base.rb', line 159

def remove_attribute_native(attr)
  attr.remove
end

.remove_declaration(_native_doc) ⇒ Object

Clear the declaration state from the native document. Called when a Declaration node is removed from a document.



211
# File 'lib/moxml/adapter/base.rb', line 211

def remove_declaration(_native_doc); end

.restore_entities(text) ⇒ Object



19
20
21
# File 'lib/moxml/adapter/base.rb', line 19

def restore_entities(text)
  Entity.restore_entities(text)
end

.sax_parse(_xml, _handler) ⇒ void

This method returns an undefined value.

Parse XML using SAX (event-driven) parsing

SAX parsing provides a memory-efficient way to process XML by triggering events as the document is parsed, rather than building a complete DOM tree.

Parameters:

Raises:



49
50
51
52
53
54
55
# File 'lib/moxml/adapter/base.rb', line 49

def sax_parse(_xml, _handler)
  raise Moxml::NotImplementedError.new(
    "sax_parse not implemented",
    feature: "sax_parse",
    adapter: name,
  )
end

.sax_supported?Boolean

Check if this adapter supports SAX parsing

Returns:

  • (Boolean)

    true if SAX parsing is supported



60
61
62
# File 'lib/moxml/adapter/base.rb', line 60

def sax_supported?
  method(:sax_parse).owner != Moxml::Adapter::Base.singleton_class
end

.set_attribute_name(attribute, name) ⇒ Object

Mutation return contract: protocol methods that may change which native a wrapper tracks (set_attribute_name, set_namespace, set_attribute_value) always return the native the wrapper must keep tracking — the same object when mutated in place, a fresh object when the adapter recreates the node.



138
139
140
141
# File 'lib/moxml/adapter/base.rb', line 138

def set_attribute_name(attribute, name)
  attribute.name = name
  attribute
end

.set_attribute_value(attribute, value) ⇒ Object



151
152
153
154
# File 'lib/moxml/adapter/base.rb', line 151

def set_attribute_value(attribute, value)
  attribute.value = value
  attribute
end

.set_namespace(_node, _namespace) ⇒ Object



143
144
145
146
147
148
149
# File 'lib/moxml/adapter/base.rb', line 143

def set_namespace(_node, _namespace)
  raise Moxml::NotImplementedError.new(
    "set_namespace not implemented",
    feature: "set_namespace",
    adapter: name,
  )
end

.set_root(_doc, _element) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/moxml/adapter/base.rb', line 23

def set_root(_doc, _element)
  raise Moxml::NotImplementedError.new(
    "set_root not implemented",
    feature: "set_root",
    adapter: name,
  )
end

.wrappers_recyclable?Boolean

Whether Node.wrap may safely memoize the wrapper for this native across calls. Adapters whose parser hands back the same Ruby object for the same logical node (nokogiri, ox, oga, rexml, leptris) opt in (default true). Adapters that mint a new Ruby object per access (libxml) opt out so the identity map does not accumulate dead entries.

Returns:

  • (Boolean)


239
240
241
# File 'lib/moxml/adapter/base.rb', line 239

def wrappers_recyclable?
  true
end