Class: Moxml::Node

Inherits:
Object
  • Object
show all
Includes:
XmlUtils
Defined in:
lib/moxml/node.rb

Constant Summary collapse

TYPES =
%i[
  element text cdata comment processing_instruction document
  declaration doctype namespace attribute unknown
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance 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_pi_target, #validate_prefix, #validate_uri

Constructor Details

#initialize(native, context) ⇒ Node

Returns a new instance of Node.



17
18
19
20
21
# File 'lib/moxml/node.rb', line 17

def initialize(native, context)
  @context = context
  # @native = adapter.patch_node(native)
  @native = native
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



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

def context
  @context
end

#nativeObject (readonly)

Returns the value of attribute native.



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

def native
  @native
end

Class Method Details

.wrap(node, context) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/moxml/node.rb', line 189

def self.wrap(node, context)
  return nil if node.nil?

  klass = case adapter(context).node_type(node)
          when :element then Element
          when :text then Text
          when :cdata then Cdata
          when :comment then Comment
          when :processing_instruction then ProcessingInstruction
          when :document then Document
          when :declaration then Declaration
          when :doctype then Doctype
          when :attribute then Attribute
          else self
          end

  klass.new(node, context)
end

Instance Method Details

#==(other) ⇒ Object



179
180
181
# File 'lib/moxml/node.rb', line 179

def ==(other)
  self.class == other.class && @native == other.native
end

#[](name) ⇒ Object

Attribute accessor - only works on Element nodes Returns nil for non-element nodes



138
139
140
141
142
143
# File 'lib/moxml/node.rb', line 138

def [](name)
  return nil unless respond_to?(:attribute)

  attr = attribute(name)
  attr&.value if attr.respond_to?(:value)
end

#add_child(node) ⇒ Object



46
47
48
49
50
# File 'lib/moxml/node.rb', line 46

def add_child(node)
  node = prepare_node(node)
  adapter.add_child(@native, node.native)
  self
end

#add_next_sibling(node) ⇒ Object



58
59
60
61
62
# File 'lib/moxml/node.rb', line 58

def add_next_sibling(node)
  node = prepare_node(node)
  adapter.add_next_sibling(@native, node.native)
  self
end

#add_previous_sibling(node) ⇒ Object



52
53
54
55
56
# File 'lib/moxml/node.rb', line 52

def add_previous_sibling(node)
  node = prepare_node(node)
  adapter.add_previous_sibling(@native, node.native)
  self
end

#at_xpath(expression, namespaces = {}) ⇒ Object



89
90
91
# File 'lib/moxml/node.rb', line 89

def at_xpath(expression, namespaces = {})
  Node.wrap(adapter.at_xpath(@native, expression, namespaces), context)
end

#childrenObject



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

def children
  NodeSet.new(
    adapter.children(@native).map { adapter.patch_node(_1, @native) },
    context,
  )
end

#cloneObject Also known as: dup

Clone the node (deep copy)



174
175
176
# File 'lib/moxml/node.rb', line 174

def clone
  Node.wrap(adapter.dup(@native), context)
end

#documentObject



23
24
25
# File 'lib/moxml/node.rb', line 23

def document
  Document.wrap(adapter.document(@native), context)
end

#each_node(&block) ⇒ Object

Recursively yield all descendant nodes Used by XPath descendant-or-self and descendant axes



166
167
168
169
170
171
# File 'lib/moxml/node.rb', line 166

def each_node(&block)
  children.each do |child|
    yield child
    child.each_node(&block) if child.respond_to?(:each_node)
  end
end

#find(xpath_expression, namespaces = {}) ⇒ Object

Convenience find methods (aliases for xpath methods)



94
95
96
# File 'lib/moxml/node.rb', line 94

def find(xpath_expression, namespaces = {})
  at_xpath(xpath_expression, namespaces)
end

#find_all(xpath_expression, namespaces = {}) ⇒ Object



98
99
100
# File 'lib/moxml/node.rb', line 98

def find_all(xpath_expression, namespaces = {})
  xpath(xpath_expression, namespaces).to_a
end

#first_childObject

Get first/last child



108
109
110
# File 'lib/moxml/node.rb', line 108

def first_child
  children.first
end

#has_children?Boolean

Check if node has any children

Returns:

  • (Boolean)


103
104
105
# File 'lib/moxml/node.rb', line 103

def has_children?
  !children.empty?
end

#last_childObject



112
113
114
# File 'lib/moxml/node.rb', line 112

def last_child
  children.last
end

#namespaceObject

Returns the namespace of this node Only applicable to Element nodes, returns nil for others



147
148
149
150
151
152
# File 'lib/moxml/node.rb', line 147

def namespace
  return nil unless element?

  ns = adapter.namespace(@native)
  ns && Namespace.new(ns, context)
end

#namespacesObject

Returns all namespace definitions on this node Only applicable to Element nodes, returns empty array for others



156
157
158
159
160
161
162
# File 'lib/moxml/node.rb', line 156

def namespaces
  return [] unless element?

  adapter.namespace_definitions(@native).map do |ns|
    Namespace.new(ns, context)
  end
end

#next_siblingObject



38
39
40
# File 'lib/moxml/node.rb', line 38

def next_sibling
  Node.wrap(adapter.next_sibling(@native), context)
end

#parentObject



27
28
29
# File 'lib/moxml/node.rb', line 27

def parent
  Node.wrap(adapter.parent(@native), context)
end

#previous_siblingObject



42
43
44
# File 'lib/moxml/node.rb', line 42

def previous_sibling
  Node.wrap(adapter.previous_sibling(@native), context)
end

#removeObject



64
65
66
67
# File 'lib/moxml/node.rb', line 64

def remove
  adapter.remove(@native)
  self
end

#replace(node) ⇒ Object



69
70
71
72
73
# File 'lib/moxml/node.rb', line 69

def replace(node)
  node = prepare_node(node)
  adapter.replace(@native, node.native)
  self
end

#textObject

Returns the text content of this node Subclasses should override this method Element and Text have their own implementations



119
120
121
122
123
124
125
126
127
# File 'lib/moxml/node.rb', line 119

def text
  if respond_to?(:content)
    content
  elsif respond_to?(:children)
    children.select { |c| c.is_a?(Text) }.map(&:content).join
  else
    ""
  end
end

#to_xml(options = {}) ⇒ Object



75
76
77
78
79
80
81
82
83
# File 'lib/moxml/node.rb', line 75

def to_xml(options = {})
  # 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
  serialize_options = default_options.merge(options)
  serialize_options[:no_declaration] = !should_include_declaration?(options)

  adapter.serialize(@native, serialize_options)
end

#xpath(expression, namespaces = {}) ⇒ Object



85
86
87
# File 'lib/moxml/node.rb', line 85

def xpath(expression, namespaces = {})
  NodeSet.new(adapter.xpath(@native, expression, namespaces), context)
end