Class: Leptris::XML::Element

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

Instance Attribute Summary

Attributes inherited from Node

#c_ptr, #document

Instance Method Summary collapse

Methods inherited from Node

#<=>, #==, #cdata?, #child, #children, #comment?, #css_path, #element?, #element_children, #first_element_child, #initialize, #inspect, #last_element_child, #line, #next_element, #next_sibling, #parent, #path, #previous_element, #previous_sibling, #processing_instruction?, #text?, #traverse, #type, #unlink, wrap

Methods included from Searchable

#at, #at_css, #at_xpath, #css, #search, #xpath

Constructor Details

This class inherits a constructor from Leptris::XML::Node

Instance Method Details

#<<Object



91
92
93
94
95
96
# File 'lib/leptris/xml/element.rb', line 91

def add_child(node)
  status = Leptris::XML::FFI.leptris_element_append_child(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

#[](key) ⇒ Object Also known as: attr, get_attribute



28
29
30
# File 'lib/leptris/xml/element.rb', line 28

def [](key)
  Leptris::XML::FFI.leptris_element_attribute(@c_ptr, key.to_s)
end

#[]=(key, value) ⇒ Object Also known as: set_attribute



34
35
36
37
38
39
# File 'lib/leptris/xml/element.rb', line 34

def []=(key, value)
  status = Leptris::XML::FFI.leptris_element_set_attribute(@c_ptr, key.to_s, value.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  value
end

#add_child(node_or_markup) ⇒ Object



85
86
87
88
89
90
# File 'lib/leptris/xml/element.rb', line 85

def add_child(node)
  status = Leptris::XML::FFI.leptris_element_append_child(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

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



256
257
258
259
260
261
262
# File 'lib/leptris/xml/element.rb', line 256

def add_namespace_definition(prefix, href)
  status = Leptris::XML::FFI.leptris_element_add_namespace_definition(
    @c_ptr, prefix.to_s, href.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  Leptris::XML::Namespace.new(self, href.to_s, prefix: prefix.nil? ? nil : prefix.to_s)
end

#add_next_sibling(node) ⇒ Object



100
101
102
103
104
105
# File 'lib/leptris/xml/element.rb', line 100

def add_next_sibling(node)
  status = Leptris::XML::FFI.leptris_element_insert_after(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

#add_previous_sibling(node) ⇒ Object



107
108
109
110
111
112
# File 'lib/leptris/xml/element.rb', line 107

def add_previous_sibling(node)
  status = Leptris::XML::FFI.leptris_element_insert_before(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

#attribute_nodesObject



76
77
78
79
80
81
82
83
# File 'lib/leptris/xml/element.rb', line 76

def attribute_nodes
  count = Leptris::XML::FFI.leptris_element_attribute_count(@c_ptr)
  count.times.map do |i|
    name = Leptris::XML::FFI.leptris_element_attribute_name_at(@c_ptr, i)
    value = Leptris::XML::FFI.leptris_element_attribute_value_at(@c_ptr, i)
    Leptris::XML::Attr.new(name, value, self)
  end
end

#attributesObject



65
66
67
68
69
70
71
72
73
74
# File 'lib/leptris/xml/element.rb', line 65

def attributes
  count = Leptris::XML::FFI.leptris_element_attribute_count(@c_ptr)
  result = {}
  count.times do |i|
    name = Leptris::XML::FFI.leptris_element_attribute_name_at(@c_ptr, i)
    value = Leptris::XML::FFI.leptris_element_attribute_value_at(@c_ptr, i)
    result[name] = Leptris::XML::Attr.new(name, value, self)
  end
  result
end

#canonicalize(version = Leptris::XML::FFI::C14N_1_0, inclusive_namespaces = nil, with_comments: false, exclusive: false, mode: nil) ⇒ Object Also known as: c14n



240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/leptris/xml/element.rb', line 240

def canonicalize(version = Leptris::XML::FFI::C14N_1_0,
                 inclusive_namespaces = nil,
                 with_comments: false,
                 exclusive: false,
                 mode: nil)
  resolved_mode = mode || (exclusive ? Leptris::XML::FFI::C14N_MODE_EXCLUSIVE
                                     : Leptris::XML::FFI::C14N_MODE_CANONICAL)
  ns_ptr, _anchor = Leptris::XML.c14n_build_ns_pointer(inclusive_namespaces)
  flags = with_comments ? 1 : 0
  str_ptr = Leptris::XML::FFI.leptris_c14n_canonicalize_subtree_ex(
    @c_ptr, version, resolved_mode, ns_ptr, flags)
  return "" if str_ptr.null?
  str_ptr.read_string.tap { Leptris::XML::FFI.leptris_free_string(str_ptr) }
end

#children=(node_or_nodes) ⇒ Object



121
122
123
124
125
# File 'lib/leptris/xml/element.rb', line 121

def children=(node_or_nodes)
  # Remove existing children, then attach the new ones in source order.
  Leptris::XML::FFI.leptris_element_remove_children(@c_ptr)
  Array(node_or_nodes).each { |n| add_child(n) }
end

#contentObject



17
18
19
# File 'lib/leptris/xml/element.rb', line 17

def content
  Leptris::XML::FFI.leptris_element_text(@c_ptr)
end

#content=(new_content) ⇒ Object



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

def content=(new_content)
  status = Leptris::XML::FFI.leptris_element_set_text(@c_ptr, new_content.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  new_content
end

#default_namespace=(href) ⇒ Object



265
266
267
268
269
270
# File 'lib/leptris/xml/element.rb', line 265

def default_namespace=(href)
  status = Leptris::XML::FFI.leptris_element_set_default_namespace(@c_ptr, href.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  href
end

#dupObject Also known as: clone



169
170
171
172
173
# File 'lib/leptris/xml/element.rb', line 169

def dup
  copy_ptr = Leptris::XML::FFI.leptris_element_copy(@c_ptr, @document.c_ptr)
  raise Leptris::XML::Error, "leptris_element_copy failed" if copy_ptr.null?
  Leptris::XML::Element.new(copy_ptr, @document)
end

#key?(name) ⇒ Boolean Also known as: has_attribute?

Returns:

  • (Boolean)


42
43
44
# File 'lib/leptris/xml/element.rb', line 42

def key?(name)
  !Leptris::XML::FFI.leptris_element_attribute(@c_ptr, name.to_s).nil?
end

#keysObject



55
56
57
58
# File 'lib/leptris/xml/element.rb', line 55

def keys
  count = Leptris::XML::FFI.leptris_element_attribute_count(@c_ptr)
  count.times.map { |i| Leptris::XML::FFI.leptris_element_attribute_name_at(@c_ptr, i) }
end

#nameObject Also known as: node_name



4
5
6
# File 'lib/leptris/xml/element.rb', line 4

def name
  Leptris::XML::FFI.leptris_element_name(@c_ptr)
end

#name=(new_name) ⇒ Object Also known as: node_name=



9
10
11
12
13
14
# File 'lib/leptris/xml/element.rb', line 9

def name=(new_name)
  status = Leptris::XML::FFI.leptris_element_set_name(@c_ptr, new_name)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  new_name
end

#namespaceObject



198
199
200
201
202
# File 'lib/leptris/xml/element.rb', line 198

def namespace
  uri = Leptris::XML::FFI.leptris_element_namespace(@c_ptr)
  return nil if uri.nil? || uri.empty?
  Leptris::XML::Namespace.new(self, uri)
end

#namespace_definitionsObject



204
205
206
207
208
209
210
211
# File 'lib/leptris/xml/element.rb', line 204

def namespace_definitions
  count = Leptris::XML::FFI.leptris_element_namespace_count(@c_ptr)
  count.times.map do |i|
    prefix = Leptris::XML::FFI.leptris_element_namespace_decl_prefix(@c_ptr, i)
    uri = Leptris::XML::FFI.leptris_element_namespace_decl_uri(@c_ptr, i)
    Leptris::XML::Namespace.new(self, uri, prefix: prefix)
  end
end

#namespacesObject



213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/leptris/xml/element.rb', line 213

def namespaces
  scopes = {}
  node = self
  while node.is_a?(Leptris::XML::Element)
    node.namespace_definitions.each do |ns|
      key = ns.prefix ? "xmlns:#{ns.prefix}" : "xmlns"
      scopes[key] ||= ns.href
    end
    node = node.parent
  end
  scopes
end

#prepend_child(node) ⇒ Object



93
94
95
96
97
98
# File 'lib/leptris/xml/element.rb', line 93

def prepend_child(node)
  status = Leptris::XML::FFI.leptris_element_prepend_child(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

#remove_attribute(name) ⇒ Object Also known as: delete



47
48
49
50
51
52
# File 'lib/leptris/xml/element.rb', line 47

def remove_attribute(name)
  status = Leptris::XML::FFI.leptris_element_remove_attribute(@c_ptr, name.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  self
end

#remove_child(node) ⇒ Object



114
115
116
117
118
119
# File 'lib/leptris/xml/element.rb', line 114

def remove_child(node)
  status = Leptris::XML::FFI.leptris_element_remove_child(@c_ptr, node.c_ptr)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  node
end

#remove_namespace_definition(prefix) ⇒ Object



272
273
274
275
276
277
# File 'lib/leptris/xml/element.rb', line 272

def remove_namespace_definition(prefix)
  status = Leptris::XML::FFI.leptris_element_remove_namespace_definition(@c_ptr, prefix.to_s)
  raise Leptris::XML::Error,
    Leptris::XML::FFI.leptris_status_string(status) unless status == Leptris::XML::FFI::LEPTRIS_OK
  self
end

#replace(new_node) ⇒ Object

Replace this element with new_node in the parent's child list. new_node must belong to the same document. Returns new_node.



129
130
131
132
133
134
135
# File 'lib/leptris/xml/element.rb', line 129

def replace(new_node)
  parent = self.parent
  raise Leptris::XML::Error, "cannot replace a node with no parent" unless parent
  add_next_sibling(new_node)
  parent.remove_child(self)
  new_node
end

#swap(new_node) ⇒ Object

Like #replace but returns self for chaining.



138
139
140
141
# File 'lib/leptris/xml/element.rb', line 138

def swap(new_node)
  replace(new_node)
  self
end

#to_xml(indent: 0, no_decl: false, encoding: nil) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/leptris/xml/element.rb', line 226

def to_xml(indent: 0, no_decl: false, encoding: nil)
  opts = Leptris::XML::FFI::SerializeOptions.new
  opts[:indent] = indent.to_i
  opts[:xml_declaration] = no_decl ? 0 : 1
  enc_ptr = nil
  if encoding
    enc_ptr = ::FFI::MemoryPointer.from_string(encoding.to_s)
    opts[:encoding] = enc_ptr
  end
  str_ptr = Leptris::XML::FFI.leptris_element_serialize(@c_ptr, opts.pointer)
  return "" if str_ptr.null?
  str_ptr.read_string.tap { Leptris::XML::FFI.leptris_free_string(str_ptr) }
end

#valuesObject



60
61
62
63
# File 'lib/leptris/xml/element.rb', line 60

def values
  count = Leptris::XML::FFI.leptris_element_attribute_count(@c_ptr)
  count.times.map { |i| Leptris::XML::FFI.leptris_element_attribute_value_at(@c_ptr, i) }
end

#wrap(node_or_markup) ⇒ Object

Wrap this element in a new element parsed from markup or a dup of node. The wrapper takes this element's place in the tree, and this element becomes its only child. Returns self for chaining.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/leptris/xml/element.rb', line 146

def wrap(node_or_markup)
  wrapper =
    case node_or_markup
    when Leptris::XML::Element then node_or_markup.dup
    when String
      frag_doc = Leptris::XML::Document.parse(node_or_markup)
      frag_doc.root or raise Leptris::XML::Error, "wrap markup has no root element"
    else
      raise ArgumentError, "wrap expects a String or Element, got #{node_or_markup.class}"
    end

  parent = self.parent
  raise Leptris::XML::Error, "cannot wrap a node with no parent" unless parent

  # Insert wrapper at self's position, then move self into wrapper.
  # add_child moves self (unlinks from old parent first), so no explicit
  # remove_child needed — and trying to remove after the move corrupts
  # the C tree (libleptris silently handles non-child args badly).
  add_next_sibling(wrapper)
  wrapper.add_child(self)
  self
end