Class: Moxml::Element

Inherits:
Node
  • Object
show all
Defined in:
lib/moxml/element.rb

Constant Summary

Constants inherited from Node

Node::TYPES

Instance Attribute Summary

Attributes inherited from Node

#context, #native, #parent_node

Instance Method Summary collapse

Methods inherited from Node

#==, adapter, #add_child, #add_next_sibling, #add_previous_sibling, #after, #ancestors, #at_xpath, #before, #blank?, #children, #descendants, #document, #dup, #each, #each_node, #find, #first_child, #following_siblings, #has_children?, #initialize, #last_child, #line_number, #materialize, #next_sibling, node_type_map, #outer_xml, #parent, #path, #preceding_siblings, #previous_sibling, #refresh_native!, #remove, #replace, #to_xml, wrap, #xpath

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

This class inherits a constructor from Moxml::Node

Instance Method Details

#[](name) ⇒ Object

Unified XML-correct name resolution (see AttributeResolver): bare names match only no-namespace attributes; prefixed names resolve through in-scope declarations to expanded names.



51
52
53
# File 'lib/moxml/element.rb', line 51

def [](name)
  Moxml::AttributeResolver.resolve(self, name)&.value
end

#[]=(name, value) ⇒ Object

Write path shares the resolver's expanded-name semantics (see AttributeResolver.assign): bare names target no-namespace attributes only; prefixed names replace by namespace URI and require a declared prefix. Cache coherence is the resolver's.



44
45
46
# File 'lib/moxml/element.rb', line 44

def []=(name, value)
  Moxml::AttributeResolver.assign(self, name, normalize_xml_value(value))
end

#add_namespace(prefix, uri) ⇒ Object Also known as: add_namespace_definition



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/moxml/element.rb', line 77

def add_namespace(prefix, uri)
  adapter.create_namespace(@native, prefix, uri,
                           namespace_validation_mode: context.config.namespace_validation_mode)
  invalidate_namespace_cache!
  self
rescue ValidationError => e
  # Re-raise as NamespaceError, provide attributes for error context
  # but the to_s will only add details if provided
  raise Moxml::NamespaceError.new(
    e.message,
    prefix: prefix,
    uri: uri,
    element: self,
  )
end

#attribute(name) ⇒ Object



55
56
57
# File 'lib/moxml/element.rb', line 55

def attribute(name)
  Moxml::AttributeResolver.resolve(self, name)
end

#attributesObject



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

def attributes
  @attributes ||= adapter.attributes(@native).map do |attr|
    a = Attribute.new(attr, context)
    a.parent_node = self
    a
  end
end

#expanded_nameObject

Returns the expanded name including namespace prefix



20
21
22
23
24
25
26
# File 'lib/moxml/element.rb', line 20

def expanded_name
  if namespace_prefix && !namespace_prefix.empty?
    "#{namespace_prefix}:#{name}"
  else
    name
  end
end

#find_all(xpath) ⇒ Object



207
208
209
# File 'lib/moxml/element.rb', line 207

def find_all(xpath)
  xpath(xpath).to_a
end

#find_element(xpath) ⇒ Object

Convenience find methods



203
204
205
# File 'lib/moxml/element.rb', line 203

def find_element(xpath)
  at_xpath(xpath)
end

#get(attr_name) ⇒ Object

Returns attribute value by name (used by XPath engine)



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

def get(attr_name)
  self[attr_name]
end

#identifierString

Returns the primary identifier for this element (its tag name)

Returns:

  • (String)

    the element name



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

def identifier
  name
end

#in_scope_namespacesObject

Returns all namespaces in scope for this element, including those inherited from ancestor elements.



124
125
126
127
128
129
130
131
132
133
# File 'lib/moxml/element.rb', line 124

def in_scope_namespaces
  generation = context.namespace_scope_generation
  if @in_scope_namespaces.nil? || @in_scope_generation != generation
    @in_scope_namespaces = adapter.in_scope_namespaces(@native).map do |ns|
      Namespace.new(ns, context)
    end
    @in_scope_generation = generation
  end
  @in_scope_namespaces
end

#inner_textObject



152
153
154
155
# File 'lib/moxml/element.rb', line 152

def inner_text
  text = raw_inner_text
  adapter.restore_entities(text)
end

#inner_xmlObject



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

def inner_xml
  adapter.inner_xml(@native)
end

#inner_xml=(xml) ⇒ Object



167
168
169
170
171
172
# File 'lib/moxml/element.rb', line 167

def inner_xml=(xml)
  wrapper = "_moxml_inner_#{Process.pid}_#{object_id}"
  doc = context.parse("<#{wrapper}>#{xml}</#{wrapper}>")
  adapter.replace_children(@native, doc.root.children.map(&:native))
  invalidate_children_cache!
end

#invalidate_attribute_cache!Object

Called by Attribute#remove to invalidate the cached attributes



217
218
219
# File 'lib/moxml/element.rb', line 217

def invalidate_attribute_cache!
  @attributes = nil
end

#invalidate_namespace_cache!Object

Clear the namespace caches and bump the context's scope generation so every wrapper — including ones not reachable from any children cache — recomputes on next read.



224
225
226
227
228
# File 'lib/moxml/element.rb', line 224

def invalidate_namespace_cache!
  @namespaces = nil
  @in_scope_namespaces = nil
  context.bump_namespace_scope_generation
end

#nameObject



5
6
7
# File 'lib/moxml/element.rb', line 5

def name
  adapter.node_name(@native)
end

#name=(value) ⇒ Object



9
10
11
# File 'lib/moxml/element.rb', line 9

def name=(value)
  adapter.set_node_name(@native, value)
end

#namespaceObject

it's NOT the same as namespaces.first



95
96
97
98
# File 'lib/moxml/element.rb', line 95

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

#namespace=(ns_or_hash) ⇒ Object

add the prefix to the element name and add the namespace to the list of namespace definitions



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/moxml/element.rb', line 102

def namespace=(ns_or_hash)
  if ns_or_hash.is_a?(Hash)
    adapter.set_namespace(
      @native,
      adapter.create_namespace(@native, *ns_or_hash.to_a.first,
                               namespace_validation_mode: context.config.namespace_validation_mode),
    )
  else
    adapter.set_namespace(@native, ns_or_hash&.native)
  end
  invalidate_namespace_cache!
end

#namespace_nameObject

Returns the namespace URI of this element (alias for namespace_uri)



136
137
138
# File 'lib/moxml/element.rb', line 136

def namespace_name
  namespace_uri
end

#namespace_prefixObject

Returns the namespace prefix of this element



29
30
31
32
# File 'lib/moxml/element.rb', line 29

def namespace_prefix
  ns = namespace
  ns&.prefix
end

#namespace_uriObject

Returns the namespace URI of this element



35
36
37
38
# File 'lib/moxml/element.rb', line 35

def namespace_uri
  ns = namespace
  ns&.uri
end

#namespacesObject Also known as: namespace_definitions



115
116
117
118
119
# File 'lib/moxml/element.rb', line 115

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

#nodesObject

Alias for children (used by XPath engine)



212
213
214
# File 'lib/moxml/element.rb', line 212

def nodes
  children
end

#raw_inner_textObject

Returns inner text without entity marker restoration. Used internally when raw content with markers is needed (e.g., for DOM construction).



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

def raw_inner_text
  adapter.inner_text(@native)
end

#remove_attribute(name) ⇒ Object



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

def remove_attribute(name)
  Moxml::AttributeResolver.remove(self, name)
  self
end

#set_attributes(attributes_hash) ⇒ Object

Bulk attribute setting



191
192
193
194
# File 'lib/moxml/element.rb', line 191

def set_attributes(attributes_hash)
  attributes_hash.each { |name, value| self[name] = value }
  self
end

#textObject Also known as: content



140
141
142
143
# File 'lib/moxml/element.rb', line 140

def text
  val = adapter.text_content(@native)
  adapter.restore_entities(val)
end

#text=(content) ⇒ Object



147
148
149
150
# File 'lib/moxml/element.rb', line 147

def text=(content)
  adapter.set_text_content(@native, normalize_xml_value(content))
  invalidate_children_cache!
end

#with_attribute(name, value) ⇒ Object

Fluent interface methods



175
176
177
178
# File 'lib/moxml/element.rb', line 175

def with_attribute(name, value)
  self[name] = value
  self
end

#with_child(child) ⇒ Object

Chainable child addition



197
198
199
200
# File 'lib/moxml/element.rb', line 197

def with_child(child)
  add_child(child)
  self
end

#with_namespace(prefix, uri) ⇒ Object



180
181
182
183
# File 'lib/moxml/element.rb', line 180

def with_namespace(prefix, uri)
  add_namespace(prefix, uri)
  self
end

#with_text(content) ⇒ Object



185
186
187
188
# File 'lib/moxml/element.rb', line 185

def with_text(content)
  self.text = content
  self
end