Class: Moxml::Adapter::Oga

Inherits:
Base
  • Object
show all
Defined in:
lib/moxml/adapter/oga.rb

Class Method Summary collapse

Methods inherited from Base

create_cdata, create_comment, create_declaration, create_doctype, create_element, create_namespace, create_processing_instruction, create_text, duplicate_node, patch_node, set_attribute_name, set_attribute_value

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

Class Method Details

.add_child(element, child_or_text) ⇒ Object



206
207
208
209
210
211
212
213
214
215
# File 'lib/moxml/adapter/oga.rb', line 206

def add_child(element, child_or_text)
  child =
    if child_or_text.is_a?(String)
      create_native_text(child_or_text)
    else
      child_or_text
    end

  element.children << child
end

.add_next_sibling(node, sibling) ⇒ Object



228
229
230
231
232
233
234
235
236
237
# File 'lib/moxml/adapter/oga.rb', line 228

def add_next_sibling(node, sibling)
  if node.parent == sibling.parent
    # Oga doesn't manipulate children of the same parent
    dup_sibling = node.node_set.delete(sibling)
    index = node.node_set.index(node) + 1
    node.node_set.insert(index, dup_sibling)
  else
    node.after(sibling)
  end
end

.add_previous_sibling(node, sibling) ⇒ Object



217
218
219
220
221
222
223
224
225
226
# File 'lib/moxml/adapter/oga.rb', line 217

def add_previous_sibling(node, sibling)
  if node.parent == sibling.parent
    # Oga doesn't manipulate children of the same parent
    dup_sibling = node.node_set.delete(sibling)
    index = node.node_set.index(node)
    node.node_set.insert(index, dup_sibling)
  else
    node.before(sibling)
  end
end

.at_xpath(node, expression, namespaces = nil) ⇒ Object



321
322
323
324
325
# File 'lib/moxml/adapter/oga.rb', line 321

def at_xpath(node, expression, namespaces = nil)
  node.at_xpath(expression, namespaces: namespaces)
rescue ::Oga::XPath::Error => e
  raise Moxml::XPathError, e.message
end

.attribute_element(attr) ⇒ Object



168
169
170
# File 'lib/moxml/adapter/oga.rb', line 168

def attribute_element(attr)
  attr.element
end

.attributes(element) ⇒ Object



172
173
174
175
176
177
178
179
# File 'lib/moxml/adapter/oga.rb', line 172

def attributes(element)
  return [] unless element.respond_to?(:attributes)

  # remove attributes-namespaces
  element.attributes.reject do |attr|
    attr.name == ::Oga::XML::Element::XMLNS_PREFIX || attr.namespace_name == ::Oga::XML::Element::XMLNS_PREFIX
  end
end

.cdata_content(node) ⇒ Object



274
275
276
# File 'lib/moxml/adapter/oga.rb', line 274

def cdata_content(node)
  node.text
end

.children(node) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/moxml/adapter/oga.rb', line 131

def children(node)
  all_children = []

  all_children += [node.xml_declaration, node.doctype].compact if node.is_a?(::Oga::XML::Document)

  return all_children unless node.respond_to?(:children)

  all_children + node.children.reject do |child|
    child.is_a?(::Oga::XML::Text) &&
      child.text.strip.empty? &&
      !(child.previous.nil? && child.next.nil?)
  end
end

.comment_content(node) ⇒ Object



282
283
284
# File 'lib/moxml/adapter/oga.rb', line 282

def comment_content(node)
  node.text
end

.create_document(_native_doc = nil) ⇒ Object



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

def create_document(_native_doc = nil)
  ::Oga::XML::Document.new
end

.create_native_cdata(content) ⇒ Object



39
40
41
# File 'lib/moxml/adapter/oga.rb', line 39

def create_native_cdata(content)
  ::Oga::XML::Cdata.new(text: content)
end

.create_native_comment(content) ⇒ Object



43
44
45
# File 'lib/moxml/adapter/oga.rb', line 43

def create_native_comment(content)
  ::Oga::XML::Comment.new(text: content)
end

.create_native_declaration(version, encoding, standalone) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/moxml/adapter/oga.rb', line 57

def create_native_declaration(version, encoding, standalone)
  attrs = {
    version: version,
    encoding: encoding,
    standalone: standalone
  }.compact
  ::Moxml::Adapter::CustomizedOga::XmlDeclaration.new(attrs)
end

.create_native_doctype(name, external_id, system_id) ⇒ Object



47
48
49
50
51
# File 'lib/moxml/adapter/oga.rb', line 47

def create_native_doctype(name, external_id, system_id)
  ::Oga::XML::Doctype.new(
    name: name, public_id: external_id, system_id: system_id, type: "PUBLIC"
  )
end

.create_native_element(name) ⇒ Object



31
32
33
# File 'lib/moxml/adapter/oga.rb', line 31

def create_native_element(name)
  ::Oga::XML::Element.new(name: name)
end

.create_native_namespace(element, prefix, uri) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/moxml/adapter/oga.rb', line 78

def create_native_namespace(element, prefix, uri)
  ns = element.available_namespaces[prefix]
  return ns unless ns.nil?

  # Oga creates an attribute and registers a namespace
  set_attribute(element, [::Oga::XML::Element::XMLNS_PREFIX, prefix].compact.join(":"), uri)
  element.register_namespace(prefix, uri)
  ::Oga::XML::Namespace.new(name: prefix, uri: uri)
end

.create_native_processing_instruction(target, content) ⇒ Object



53
54
55
# File 'lib/moxml/adapter/oga.rb', line 53

def create_native_processing_instruction(target, content)
  ::Oga::XML::ProcessingInstruction.new(name: target, text: content)
end

.create_native_text(content) ⇒ Object



35
36
37
# File 'lib/moxml/adapter/oga.rb', line 35

def create_native_text(content)
  ::Oga::XML::Text.new(text: content)
end

.declaration_attribute(declaration, attr_name) ⇒ Object



66
67
68
69
70
# File 'lib/moxml/adapter/oga.rb', line 66

def declaration_attribute(declaration, attr_name)
  return unless ::Moxml::Declaration::ALLOWED_ATTRIBUTES.include?(attr_name.to_s)

  declaration.public_send(attr_name)
end

.document(node) ⇒ Object



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

def document(node)
  current = node
  current = current.parent while parent(current)

  current
end

.get_attribute(element, name) ⇒ Object



193
194
195
# File 'lib/moxml/adapter/oga.rb', line 193

def get_attribute(element, name)
  element.attribute(name.to_s)
end

.get_attribute_value(element, name) ⇒ Object



197
198
199
# File 'lib/moxml/adapter/oga.rb', line 197

def get_attribute_value(element, name)
  element[name.to_s]
end

.inner_text(node) ⇒ Object



256
257
258
259
260
261
262
263
# File 'lib/moxml/adapter/oga.rb', line 256

def inner_text(node)
  if node.respond_to?(:inner_text)
    node.inner_text
  else
    # Oga::XML::Text node for example
    node.text
  end
end

.namespace(element) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
# File 'lib/moxml/adapter/oga.rb', line 92

def namespace(element)
  if element.respond_to?(:namespace)
    element.namespace
  elsif element.respond_to?(:namespaces)
    element.namespaces.values.last
  end
rescue NoMethodError
  # Oga attributes fail with NoMethodError:
  # undefined method `available_namespaces' for nil:NilClass
  nil
end

.namespace_definitions(node) ⇒ Object



309
310
311
312
313
# File 'lib/moxml/adapter/oga.rb', line 309

def namespace_definitions(node)
  return [] unless node.respond_to?(:namespaces)

  node.namespaces.values
end

.namespace_prefix(namespace) ⇒ Object



298
299
300
301
302
303
# File 'lib/moxml/adapter/oga.rb', line 298

def namespace_prefix(namespace)
  # nil for the default namespace
  return if namespace.name == ::Oga::XML::Element::XMLNS_PREFIX

  namespace.name
end

.namespace_uri(namespace) ⇒ Object



305
306
307
# File 'lib/moxml/adapter/oga.rb', line 305

def namespace_uri(namespace)
  namespace.uri
end

.next_sibling(node) ⇒ Object



149
150
151
# File 'lib/moxml/adapter/oga.rb', line 149

def next_sibling(node)
  node.next
end

.node_name(node) ⇒ Object



123
124
125
# File 'lib/moxml/adapter/oga.rb', line 123

def node_name(node)
  node.name
end

.node_type(node) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/moxml/adapter/oga.rb', line 108

def node_type(node)
  case node
  when ::Oga::XML::Element then :element
  when ::Oga::XML::Text then :text
  when ::Oga::XML::Cdata then :cdata
  when ::Oga::XML::Comment then :comment
  when ::Oga::XML::Attribute then :attribute
  when ::Oga::XML::Namespace then :namespace
  when ::Oga::XML::ProcessingInstruction then :processing_instruction
  when ::Oga::XML::Document then :document
  when ::Oga::XML::Doctype then :doctype
  else :unknown
  end
end

.parent(node) ⇒ Object



145
146
147
# File 'lib/moxml/adapter/oga.rb', line 145

def parent(node)
  node.parent if node.respond_to?(:parent)
end

.parse(xml, options = {}) ⇒ Object



17
18
19
20
21
22
23
24
25
# File 'lib/moxml/adapter/oga.rb', line 17

def parse(xml, options = {})
  native_doc = begin
    ::Oga.parse_xml(xml, strict: options[:strict])
  rescue LL::ParserError => e
    raise Moxml::ParseError, e.message
  end

  DocumentBuilder.new(Context.new(:oga)).build(native_doc)
end

.previous_sibling(node) ⇒ Object



153
154
155
# File 'lib/moxml/adapter/oga.rb', line 153

def previous_sibling(node)
  node.previous
end

.processing_instruction_content(node) ⇒ Object



290
291
292
# File 'lib/moxml/adapter/oga.rb', line 290

def processing_instruction_content(node)
  node.text
end

.processing_instruction_target(node) ⇒ Object



104
105
106
# File 'lib/moxml/adapter/oga.rb', line 104

def processing_instruction_target(node)
  node.name
end

.remove(node) ⇒ Object



239
240
241
# File 'lib/moxml/adapter/oga.rb', line 239

def remove(node)
  node.remove
end

.remove_attribute(element, name) ⇒ Object



201
202
203
204
# File 'lib/moxml/adapter/oga.rb', line 201

def remove_attribute(element, name)
  attr = element.attribute(name.to_s)
  element.attributes.delete(attr) if attr
end

.replace(node, new_node) ⇒ Object



243
244
245
# File 'lib/moxml/adapter/oga.rb', line 243

def replace(node, new_node)
  node.replace(new_node)
end

.replace_children(node, new_children) ⇒ Object



247
248
249
250
# File 'lib/moxml/adapter/oga.rb', line 247

def replace_children(node, new_children)
  node.children = []
  new_children.each { |child| add_child(node, child) }
end

.root(document) ⇒ Object



164
165
166
# File 'lib/moxml/adapter/oga.rb', line 164

def root(document)
  document.children.find { |node| node.is_a?(::Oga::XML::Element) }
end

.serialize(node, _options = {}) ⇒ Object



327
328
329
330
# File 'lib/moxml/adapter/oga.rb', line 327

def serialize(node, _options = {})
  # Expand empty tags, encode attributes, etc
  ::Moxml::Adapter::CustomizedOga::XmlGenerator.new(node).to_xml
end

.set_attribute(element, name, value) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/moxml/adapter/oga.rb', line 181

def set_attribute(element, name, value)
  namespace_name = nil
  namespace_name, name = name.to_s.split(":", 2) if name.to_s.include?(":")

  attr = ::Oga::XML::Attribute.new(
    name: name.to_s,
    namespace_name: namespace_name,
    value: value.to_s
  )
  element.add_attribute(attr)
end

.set_cdata_content(node, content) ⇒ Object



278
279
280
# File 'lib/moxml/adapter/oga.rb', line 278

def set_cdata_content(node, content)
  node.text = content
end

.set_comment_content(node, content) ⇒ Object



286
287
288
# File 'lib/moxml/adapter/oga.rb', line 286

def set_comment_content(node, content)
  node.text = content
end

.set_declaration_attribute(declaration, attr_name, value) ⇒ Object



72
73
74
75
76
# File 'lib/moxml/adapter/oga.rb', line 72

def set_declaration_attribute(declaration, attr_name, value)
  return unless ::Moxml::Declaration::ALLOWED_ATTRIBUTES.include?(attr_name.to_s)

  declaration.public_send("#{attr_name}=", value)
end

.set_namespace(element, ns_or_string) ⇒ Object



88
89
90
# File 'lib/moxml/adapter/oga.rb', line 88

def set_namespace(element, ns_or_string)
  element.namespace_name = ns_or_string.to_s
end

.set_node_name(node, name) ⇒ Object



127
128
129
# File 'lib/moxml/adapter/oga.rb', line 127

def set_node_name(node, name)
  node.name = name
end

.set_processing_instruction_content(node, content) ⇒ Object



294
295
296
# File 'lib/moxml/adapter/oga.rb', line 294

def set_processing_instruction_content(node, content)
  node.text = content
end

.set_root(doc, element) ⇒ Object



12
13
14
15
# File 'lib/moxml/adapter/oga.rb', line 12

def set_root(doc, element)
  doc.children.clear # Clear any existing children
  doc.children << element
end

.set_text_content(node, content) ⇒ Object



265
266
267
268
269
270
271
272
# File 'lib/moxml/adapter/oga.rb', line 265

def set_text_content(node, content)
  if node.respond_to?(:inner_text=)
    node.inner_text = content
  else
    # Oga::XML::Text node for example
    node.text = content
  end
end

.text_content(node) ⇒ Object



252
253
254
# File 'lib/moxml/adapter/oga.rb', line 252

def text_content(node)
  node.text
end

.xpath(node, expression, namespaces = nil) ⇒ Object



315
316
317
318
319
# File 'lib/moxml/adapter/oga.rb', line 315

def xpath(node, expression, namespaces = nil)
  node.xpath(expression, {}, namespaces: namespaces&.transform_keys(&:to_s)).to_a
rescue ::LL::ParserError => e
  raise Moxml::XPathError, e.message
end