Module: Dommy::Backend::Nokogiri

Defined in:
lib/dommy/backend/nokogiri_adapter.rb

Overview

Nokogiri (libxml2-based) backend. Mature, full XML namespace support. Default backend.

Constant Summary collapse

Element =

Class references for ‘is_a?` / type-checking from Dommy internals.

::Nokogiri::XML::Element
Document =
::Nokogiri::XML::Document
Text =
::Nokogiri::XML::Text
Comment =
::Nokogiri::XML::Comment
DocumentFragment =
::Nokogiri::XML::DocumentFragment
Node =
::Nokogiri::XML::Node

Class Method Summary collapse

Class Method Details

.add_namespace_definition(node, prefix, href) ⇒ Object



57
58
59
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 57

def add_namespace_definition(node, prefix, href)
  node.add_namespace_definition(prefix, href)
end

.attribute_nodes(node) ⇒ Object



112
113
114
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 112

def attribute_nodes(node)
  node.attribute_nodes
end

.attribute_ns_info(attr_node) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 101

def attribute_ns_info(attr_node)
  ns = attr_node.namespace
  {
    namespace_uri: ns&.href,
    prefix: ns&.prefix,
    local_name: attr_node.name,
    qualified_name: ns&.prefix ? "#{ns.prefix}:#{attr_node.name}" : attr_node.name,
    value: attr_node.value,
  }
end

.cdata_classObject



51
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 51

def cdata_class = ::Nokogiri::XML::CDATA

.create_cdata(content, doc) ⇒ Object



47
48
49
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 47

def create_cdata(content, doc)
  ::Nokogiri::XML::CDATA.new(doc, content.to_s)
end

.create_comment(content, doc) ⇒ Object



43
44
45
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 43

def create_comment(content, doc)
  ::Nokogiri::XML::Comment.new(doc, content)
end

.create_element(name, doc) ⇒ Object



35
36
37
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 35

def create_element(name, doc)
  ::Nokogiri::XML::Node.new(name, doc)
end

.create_text(content, doc) ⇒ Object



39
40
41
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 39

def create_text(content, doc)
  ::Nokogiri::XML::Text.new(content, doc)
end

.find_attr_ns(node, namespace, local_name) ⇒ Object

Finds the attribute node matching (namespace, localName). A null namespace matches only the un-namespaced attribute of that local name.



118
119
120
121
122
123
124
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 118

def find_attr_ns(node, namespace, local_name)
  if namespace.nil? || namespace.to_s.empty?
    node.attribute_nodes.find { |a| a.namespace.nil? && a.name == local_name.to_s }
  else
    node.attribute_with_ns(local_name.to_s, namespace.to_s)
  end
end

.fragment(html, owner_doc:) ⇒ Object



29
30
31
32
33
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 29

def fragment(html, owner_doc:)
  # owner_doc is unused by Nokogiri — the fragment carries its
  # own document. The Parser layer copies nodes into the target.
  ::Nokogiri::HTML5.fragment(html.to_s, max_errors: 0)
end

.get_attribute_ns(node, namespace, local_name) ⇒ Object

—– Namespaced attributes —–



63
64
65
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 63

def get_attribute_ns(node, namespace, local_name)
  find_attr_ns(node, namespace, local_name)&.value
end

.has_attribute_ns?(node, namespace, local_name) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 67

def has_attribute_ns?(node, namespace, local_name)
  !find_attr_ns(node, namespace, local_name).nil?
end

.namespace_of(node) ⇒ Object



53
54
55
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 53

def namespace_of(node)
  node.namespace
end

.parse(html) ⇒ Object



20
21
22
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 20

def parse(html)
  ::Nokogiri::HTML5(html.to_s, max_errors: 0)
end

.parse_xml(xml) ⇒ Object

Parse an XML string into an XML document (DOMParser “text/xml” etc.).



25
26
27
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 25

def parse_xml(xml)
  ::Nokogiri::XML(xml.to_s)
end

.remove_attribute_ns(node, namespace, local_name) ⇒ Object



96
97
98
99
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 96

def remove_attribute_ns(node, namespace, local_name)
  find_attr_ns(node, namespace, local_name)&.remove
  nil
end

.set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/dommy/backend/nokogiri_adapter.rb', line 71

def set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value)
  # WHATWG "set an attribute value": when an attribute with this
  # (namespace, localName) already exists, only its value changes —
  # the existing prefix/qualified name is preserved, not replaced by
  # the one in this call.
  existing = find_attr_ns(node, namespace, local_name)
  if existing
    existing.value = value.to_s
    return value.to_s
  end

  if namespace.nil? || namespace.to_s.empty?
    node[qualified_name] = value.to_s
    return value.to_s
  end

  # Defining the namespace before the qualified-name assignment lets
  # libxml2 bind the prefix to it (verified behavior). Reuse an existing
  # matching definition so repeated sets don't pile up declarations.
  node.namespace_definitions.find { |d| d.href == namespace.to_s && d.prefix == prefix } ||
    node.add_namespace_definition(prefix, namespace.to_s)
  node[qualified_name] = value.to_s
  value.to_s
end