Class: Moxml::Node
- Inherits:
-
Object
- Object
- Moxml::Node
- Includes:
- Enumerable, XmlUtils
- Defined in:
- lib/moxml/node.rb
Direct Known Subclasses
Attribute, Cdata, Comment, Declaration, Doctype, Document, Element, EntityReference, Namespace, ProcessingInstruction, Text
Constant Summary collapse
- TYPES =
%i[ element text cdata comment processing_instruction document declaration doctype namespace attribute unknown entity_reference ].freeze
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#native ⇒ Object
readonly
Returns the value of attribute native.
-
#parent_node ⇒ Object
writeonly
Internal: Set the parent node for cache invalidation tracking.
Class Method Summary collapse
- .adapter(context) ⇒ Object
-
.node_type_map ⇒ Object
Registry mapping node type symbols to wrapper classes.
- .wrap(node, context) ⇒ Object
Instance Method Summary collapse
- #==(other) ⇒ Object
- #add_child(node) ⇒ Object
- #add_next_sibling(node) ⇒ Object
- #add_previous_sibling(node) ⇒ Object
- #after(node) ⇒ Object
- #at_xpath(expression, namespaces = {}) ⇒ Object
- #before(node) ⇒ Object
- #blank? ⇒ Boolean
- #children ⇒ Object
-
#content ⇒ Object
Returns the content/value of this node as a string.
- #document ⇒ Object
-
#dup ⇒ Object
(also: #clone)
Deep copy of the node (both dup and clone create deep copies for XML nodes).
-
#each(&block) ⇒ Object
Yield direct children, enabling Enumerable on the node.
-
#each_node(&block) ⇒ Object
Recursively yield all descendant nodes Used by XPath descendant-or-self and descendant axes.
-
#find(xpath_expression, namespaces = {}) ⇒ Object
Convenience find methods (aliases for xpath methods).
- #find_all(xpath_expression, namespaces = {}) ⇒ Object
-
#first_child ⇒ Object
Get first/last child.
-
#has_children? ⇒ Boolean
Check if node has any children.
-
#identifier ⇒ String?
Returns the primary identifier for this node type For Element: the tag name For Attribute: the attribute name For ProcessingInstruction: the target For content nodes (Text, Comment, Cdata, Declaration): nil (no identifier) For Doctype: nil (not fully implemented across adapters).
-
#initialize(native, context) ⇒ Node
constructor
A new instance of Node.
- #last_child ⇒ Object
-
#namespace ⇒ Object
Returns the namespace of this node Only applicable to Element nodes, returns nil for others.
-
#namespaces ⇒ Object
Returns all namespace definitions on this node Only applicable to Element nodes, returns empty array for others.
- #next_sibling ⇒ Object
- #outer_xml ⇒ Object
- #parent ⇒ Object
- #previous_sibling ⇒ Object
-
#refresh_native!(new_native) ⇒ Object
Update native reference after identity-changing operations (e.g., LibXML doc.root= creates a new Ruby wrapper).
- #remove ⇒ Object
- #replace(node) ⇒ Object
-
#text ⇒ Object
Returns the text content of this node Subclasses should override this method Element and Text have their own implementations.
- #to_xml(options = {}) ⇒ Object
- #xpath(expression, namespaces = {}) ⇒ Object
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
Constructor Details
#initialize(native, context) ⇒ Node
Returns a new instance of Node.
15 16 17 18 19 |
# File 'lib/moxml/node.rb', line 15 def initialize(native, context) @context = context @native = native @parent_node = nil end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
13 14 15 |
# File 'lib/moxml/node.rb', line 13 def context @context end |
#native ⇒ Object (readonly)
Returns the value of attribute native.
13 14 15 |
# File 'lib/moxml/node.rb', line 13 def native @native end |
#parent_node=(value) ⇒ Object (writeonly)
Internal: Set the parent node for cache invalidation tracking. Called by NodeSet, Document, Element when establishing parent-child relationships. Public to allow cross-class usage within Moxml internals.
263 264 265 |
# File 'lib/moxml/node.rb', line 263 def parent_node=(value) @parent_node = value end |
Class Method Details
.adapter(context) ⇒ Object
271 272 273 |
# File 'lib/moxml/node.rb', line 271 def self.adapter(context) context.config.adapter end |
.node_type_map ⇒ Object
Registry mapping node type symbols to wrapper classes. Built lazily to avoid load-order issues with subclasses.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/moxml/node.rb', line 236 def self.node_type_map @node_type_map ||= { element: Element, text: Text, cdata: Cdata, comment: Comment, processing_instruction: ProcessingInstruction, document: Document, declaration: Declaration, doctype: Doctype, attribute: Attribute, entity_reference: EntityReference, }.freeze end |
.wrap(node, context) ⇒ Object
251 252 253 254 255 256 257 258 |
# File 'lib/moxml/node.rb', line 251 def self.wrap(node, context) return nil if node.nil? type = adapter(context).node_type(node) klass = node_type_map[type] || self klass.new(node, context) end |
Instance Method Details
#==(other) ⇒ Object
212 213 214 |
# File 'lib/moxml/node.rb', line 212 def ==(other) self.class == other.class && @native == other.native end |
#add_child(node) ⇒ Object
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/moxml/node.rb', line 51 def add_child(node) node = prepare_node(node) adapter.add_child(@native, node.native) # Refresh native in case adapter changed identity (e.g., LibXML doc.root=) refreshed = adapter.actual_native(node.native, @native) node.refresh_native!(refreshed) if refreshed && refreshed != node.native node.parent_node = self invalidate_children_cache! self end |
#add_next_sibling(node) ⇒ Object
69 70 71 72 73 74 |
# File 'lib/moxml/node.rb', line 69 def add_next_sibling(node) node = prepare_node(node) adapter.add_next_sibling(@native, node.native) invalidate_parent_children_cache! self end |
#add_previous_sibling(node) ⇒ Object
62 63 64 65 66 67 |
# File 'lib/moxml/node.rb', line 62 def add_previous_sibling(node) node = prepare_node(node) adapter.add_previous_sibling(@native, node.native) invalidate_parent_children_cache! self end |
#after(node) ⇒ Object
197 198 199 |
# File 'lib/moxml/node.rb', line 197 def after(node) add_next_sibling(node) end |
#at_xpath(expression, namespaces = {}) ⇒ Object
109 110 111 112 |
# File 'lib/moxml/node.rb', line 109 def at_xpath(expression, namespaces = {}) Moxml::Node.wrap(adapter.at_xpath(@native, expression, namespaces), context) end |
#before(node) ⇒ Object
193 194 195 |
# File 'lib/moxml/node.rb', line 193 def before(node) add_previous_sibling(node) end |
#blank? ⇒ Boolean
201 202 203 |
# File 'lib/moxml/node.rb', line 201 def blank? text.strip.empty? end |
#children ⇒ Object
35 36 37 38 39 40 41 |
# File 'lib/moxml/node.rb', line 35 def children @children ||= NodeSet.new( adapter.children(@native).map { adapter.patch_node(_1, @native) }, context, self, ) end |
#content ⇒ Object
Returns the content/value of this node as a string. Each subclass overrides this with type-specific semantics:
-
Text, Comment, Cdata: raw text content
-
ProcessingInstruction: instruction content
-
Attribute: attribute value
-
Element: delegates to text (descendant text concatenation)
150 151 152 |
# File 'lib/moxml/node.rb', line 150 def content "" end |
#document ⇒ Object
27 28 29 |
# File 'lib/moxml/node.rb', line 27 def document Document.wrap(adapter.document(@native), context) end |
#dup ⇒ Object Also known as: clone
Deep copy of the node (both dup and clone create deep copies for XML nodes)
206 207 208 |
# File 'lib/moxml/node.rb', line 206 def dup Moxml::Node.wrap(adapter.dup(@native), context) end |
#each(&block) ⇒ Object
Yield direct children, enabling Enumerable on the node.
183 184 185 186 187 |
# File 'lib/moxml/node.rb', line 183 def each(&block) return to_enum(:each) unless block children.each(&block) end |
#each_node(&block) ⇒ Object
Recursively yield all descendant nodes Used by XPath descendant-or-self and descendant axes
175 176 177 178 179 180 |
# File 'lib/moxml/node.rb', line 175 def each_node(&block) children.each do |child| yield child child.each_node(&block) end end |
#find(xpath_expression, namespaces = {}) ⇒ Object
Convenience find methods (aliases for xpath methods)
115 116 117 |
# File 'lib/moxml/node.rb', line 115 def find(xpath_expression, namespaces = {}) at_xpath(xpath_expression, namespaces) end |
#find_all(xpath_expression, namespaces = {}) ⇒ Object
119 120 121 |
# File 'lib/moxml/node.rb', line 119 def find_all(xpath_expression, namespaces = {}) xpath(xpath_expression, namespaces).to_a end |
#first_child ⇒ Object
Get first/last child
129 130 131 |
# File 'lib/moxml/node.rb', line 129 def first_child children.first end |
#has_children? ⇒ Boolean
Check if node has any children
124 125 126 |
# File 'lib/moxml/node.rb', line 124 def has_children? !children.empty? end |
#identifier ⇒ String?
Returns the primary identifier for this node type For Element: the tag name For Attribute: the attribute name For ProcessingInstruction: the target For content nodes (Text, Comment, Cdata, Declaration): nil (no identifier) For Doctype: nil (not fully implemented across adapters)
230 231 232 |
# File 'lib/moxml/node.rb', line 230 def identifier nil end |
#last_child ⇒ Object
133 134 135 |
# File 'lib/moxml/node.rb', line 133 def last_child children.last end |
#namespace ⇒ Object
Returns the namespace of this node Only applicable to Element nodes, returns nil for others
156 157 158 159 160 161 |
# File 'lib/moxml/node.rb', line 156 def namespace return nil unless element? ns = adapter.namespace(@native) ns && Namespace.new(ns, context) end |
#namespaces ⇒ Object
Returns all namespace definitions on this node Only applicable to Element nodes, returns empty array for others
165 166 167 168 169 170 171 |
# File 'lib/moxml/node.rb', line 165 def namespaces return [] unless element? adapter.namespace_definitions(@native).map do |ns| Namespace.new(ns, context) end end |
#next_sibling ⇒ Object
43 44 45 |
# File 'lib/moxml/node.rb', line 43 def next_sibling Moxml::Node.wrap(adapter.next_sibling(@native), context) end |
#outer_xml ⇒ Object
189 190 191 |
# File 'lib/moxml/node.rb', line 189 def outer_xml to_xml end |
#parent ⇒ Object
31 32 33 |
# File 'lib/moxml/node.rb', line 31 def parent Moxml::Node.wrap(adapter.parent(@native), context) end |
#previous_sibling ⇒ Object
47 48 49 |
# File 'lib/moxml/node.rb', line 47 def previous_sibling Moxml::Node.wrap(adapter.previous_sibling(@native), context) end |
#refresh_native!(new_native) ⇒ Object
Update native reference after identity-changing operations (e.g., LibXML doc.root= creates a new Ruby wrapper)
23 24 25 |
# File 'lib/moxml/node.rb', line 23 def refresh_native!(new_native) @native = new_native end |
#remove ⇒ Object
76 77 78 79 80 81 |
# File 'lib/moxml/node.rb', line 76 def remove invalidate_parent_children_cache! adapter.remove(@native) invalidate_children_cache! self end |
#replace(node) ⇒ Object
83 84 85 86 87 88 89 |
# File 'lib/moxml/node.rb', line 83 def replace(node) node = prepare_node(node) invalidate_parent_children_cache! adapter.replace(@native, node.native) invalidate_children_cache! self end |
#text ⇒ Object
Returns the text content of this node Subclasses should override this method Element and Text have their own implementations
140 141 142 |
# File 'lib/moxml/node.rb', line 140 def text "" end |
#to_xml(options = {}) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/moxml/node.rb', line 91 def to_xml( = {}) # Determine if we should include XML declaration # For Document nodes: check native then wrapper, unless explicitly overridden # For other nodes: default to no declaration unless explicitly set = .merge() [:no_declaration] = !should_include_declaration?() result = adapter.serialize(@native, ) result = apply_line_ending(result, [:line_ending]) # Restore entity markers to named entity references adapter.restore_entities(result) end |