Class: Moxml::Adapter::Nokogiri

Inherits:
Base
  • Object
show all
Defined in:
lib/moxml/adapter/nokogiri.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

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) ⇒ Object



196
197
198
199
200
201
202
203
204
205
# File 'lib/moxml/adapter/nokogiri.rb', line 196

def add_child(element, child)
  if node_type(child) == :doctype
    # avoid exceptions: cannot reparent Nokogiri::XML::DTD there
    element.create_internal_subset(
      child.name, child.external_id, child.system_id
    )
  else
    element.add_child(child)
  end
end

.add_next_sibling(node, sibling) ⇒ Object



211
212
213
# File 'lib/moxml/adapter/nokogiri.rb', line 211

def add_next_sibling(node, sibling)
  node.add_next_sibling(sibling)
end

.add_previous_sibling(node, sibling) ⇒ Object



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

def add_previous_sibling(node, sibling)
  node.add_previous_sibling(sibling)
end

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



278
279
280
281
282
# File 'lib/moxml/adapter/nokogiri.rb', line 278

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

.attribute_element(attr) ⇒ Object



170
171
172
# File 'lib/moxml/adapter/nokogiri.rb', line 170

def attribute_element(attr)
  attr.parent
end

.attributes(element) ⇒ Object



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

def attributes(element)
  element.attributes.values
end

.cdata_content(node) ⇒ Object



236
237
238
# File 'lib/moxml/adapter/nokogiri.rb', line 236

def cdata_content(node)
  node.content
end

.children(node) ⇒ Object



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

def children(node)
  node.children.reject do |child|
    child.text? && child.content.strip.empty? &&
      !(child.previous_sibling.nil? && child.next_sibling.nil?)
  end
end

.comment_content(node) ⇒ Object



244
245
246
# File 'lib/moxml/adapter/nokogiri.rb', line 244

def comment_content(node)
  node.content
end

.create_documentObject



34
35
36
# File 'lib/moxml/adapter/nokogiri.rb', line 34

def create_document
  ::Nokogiri::XML::Document.new
end

.create_fragmentObject



38
39
40
41
42
43
44
# File 'lib/moxml/adapter/nokogiri.rb', line 38

def create_fragment
  # document fragments are weird and should be used with caution:
  # https://github.com/sparklemotion/nokogiri/issues/572
  ::Nokogiri::XML::DocumentFragment.new(
    ::Nokogiri::XML::Document.new
  )
end

.create_native_cdata(content) ⇒ Object



54
55
56
# File 'lib/moxml/adapter/nokogiri.rb', line 54

def create_native_cdata(content)
  ::Nokogiri::XML::CDATA.new(create_document, content)
end

.create_native_comment(content) ⇒ Object



58
59
60
# File 'lib/moxml/adapter/nokogiri.rb', line 58

def create_native_comment(content)
  ::Nokogiri::XML::Comment.new(create_document, content)
end

.create_native_declaration(version, encoding, standalone) ⇒ Object



74
75
76
77
78
79
80
# File 'lib/moxml/adapter/nokogiri.rb', line 74

def create_native_declaration(version, encoding, standalone)
  ::Nokogiri::XML::ProcessingInstruction.new(
    create_document,
    "xml",
    build_declaration_attrs(version, encoding, standalone)
  )
end

.create_native_doctype(name, external_id, system_id) ⇒ Object



62
63
64
65
66
# File 'lib/moxml/adapter/nokogiri.rb', line 62

def create_native_doctype(name, external_id, system_id)
  create_document.create_internal_subset(
    name, external_id, system_id
  )
end

.create_native_element(name) ⇒ Object



46
47
48
# File 'lib/moxml/adapter/nokogiri.rb', line 46

def create_native_element(name)
  ::Nokogiri::XML::Element.new(name, create_document)
end

.create_native_namespace(element, prefix, uri) ⇒ Object



113
114
115
# File 'lib/moxml/adapter/nokogiri.rb', line 113

def create_native_namespace(element, prefix, uri)
  element.add_namespace_definition(prefix, uri)
end

.create_native_processing_instruction(target, content) ⇒ Object



68
69
70
71
72
# File 'lib/moxml/adapter/nokogiri.rb', line 68

def create_native_processing_instruction(target, content)
  ::Nokogiri::XML::ProcessingInstruction.new(
    ::Nokogiri::XML::Document.new, target, content
  )
end

.create_native_text(content) ⇒ Object



50
51
52
# File 'lib/moxml/adapter/nokogiri.rb', line 50

def create_native_text(content)
  ::Nokogiri::XML::Text.new(content, create_document)
end

.declaration_attribute(declaration, attr_name) ⇒ Object



82
83
84
85
86
87
# File 'lib/moxml/adapter/nokogiri.rb', line 82

def declaration_attribute(declaration, attr_name)
  return nil unless declaration.content

  match = declaration.content.match(/#{attr_name}="([^"]*)"/)
  match && match[1]
end

.document(node) ⇒ Object



162
163
164
# File 'lib/moxml/adapter/nokogiri.rb', line 162

def document(node)
  node.document
end

.get_attribute(element, name) ⇒ Object



182
183
184
185
# File 'lib/moxml/adapter/nokogiri.rb', line 182

def get_attribute(element, name)
  # attributes keys don't include attribute namespaces
  element.attributes[name.to_s]
end

.get_attribute_value(element, name) ⇒ Object



187
188
189
190
# File 'lib/moxml/adapter/nokogiri.rb', line 187

def get_attribute_value(element, name)
  # get the attribute value by its name including a namespace
  element[name.to_s]
end

.inner_text(node) ⇒ Object



227
228
229
230
# File 'lib/moxml/adapter/nokogiri.rb', line 227

def inner_text(node)
  text_children = node.children - node.element_children
  text_children.map(&:content).join
end

.namespace(element) ⇒ Object



105
106
107
# File 'lib/moxml/adapter/nokogiri.rb', line 105

def namespace(element)
  element.namespace
end

.namespace_definitions(node) ⇒ Object



268
269
270
# File 'lib/moxml/adapter/nokogiri.rb', line 268

def namespace_definitions(node)
  node.namespace_definitions
end

.namespace_prefix(namespace) ⇒ Object



260
261
262
# File 'lib/moxml/adapter/nokogiri.rb', line 260

def namespace_prefix(namespace)
  namespace.prefix
end

.namespace_uri(namespace) ⇒ Object



264
265
266
# File 'lib/moxml/adapter/nokogiri.rb', line 264

def namespace_uri(namespace)
  namespace.href
end

.next_sibling(node) ⇒ Object



154
155
156
# File 'lib/moxml/adapter/nokogiri.rb', line 154

def next_sibling(node)
  node.next_sibling
end

.node_name(node) ⇒ Object



130
131
132
# File 'lib/moxml/adapter/nokogiri.rb', line 130

def node_name(node)
  node.name
end

.node_type(node) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/moxml/adapter/nokogiri.rb', line 117

def node_type(node)
  case node
  when ::Nokogiri::XML::Element then :element
  when ::Nokogiri::XML::CDATA then :cdata
  when ::Nokogiri::XML::Text then :text
  when ::Nokogiri::XML::Comment then :comment
  when ::Nokogiri::XML::ProcessingInstruction then :processing_instruction
  when ::Nokogiri::XML::Document, ::Nokogiri::XML::DocumentFragment then :document
  when ::Nokogiri::XML::DTD then :doctype
  else :unknown
  end
end

.parent(node) ⇒ Object



150
151
152
# File 'lib/moxml/adapter/nokogiri.rb', line 150

def parent(node)
  node.parent
end

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



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/moxml/adapter/nokogiri.rb', line 14

def parse(xml, options = {})
  native_doc = begin
    if options[:fragment]
      ::Nokogiri::XML::DocumentFragment.parse(xml) do |config|
        config.strict.nonet
        config.recover unless options[:strict]
      end
    else
      ::Nokogiri::XML(xml, nil, options[:encoding]) do |config|
        config.strict.nonet
        config.recover unless options[:strict]
      end
    end
  rescue ::Nokogiri::XML::SyntaxError => e
    raise Moxml::ParseError.new(e.message, line: e.line, column: e.column)
  end

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

.previous_sibling(node) ⇒ Object



158
159
160
# File 'lib/moxml/adapter/nokogiri.rb', line 158

def previous_sibling(node)
  node.previous_sibling
end

.processing_instruction_content(node) ⇒ Object



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

def processing_instruction_content(node)
  node.content
end

.processing_instruction_target(node) ⇒ Object



109
110
111
# File 'lib/moxml/adapter/nokogiri.rb', line 109

def processing_instruction_target(node)
  node.name
end

.remove(node) ⇒ Object



215
216
217
# File 'lib/moxml/adapter/nokogiri.rb', line 215

def remove(node)
  node.remove
end

.remove_attribute(element, name) ⇒ Object



192
193
194
# File 'lib/moxml/adapter/nokogiri.rb', line 192

def remove_attribute(element, name)
  element.remove_attribute(name.to_s)
end

.replace(node, new_node) ⇒ Object



219
220
221
# File 'lib/moxml/adapter/nokogiri.rb', line 219

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

.replace_children(node, new_children) ⇒ Object



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

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

.root(document) ⇒ Object



166
167
168
# File 'lib/moxml/adapter/nokogiri.rb', line 166

def root(document)
  document.respond_to?(:root) ? document.root : document.children.first
end

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



284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/moxml/adapter/nokogiri.rb', line 284

def serialize(node, options = {})
  save_options = ::Nokogiri::XML::Node::SaveOptions::AS_XML

  # Don't force expand empty elements if they're really empty
  save_options |= ::Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS if options[:expand_empty]
  save_options |= ::Nokogiri::XML::Node::SaveOptions::FORMAT if options[:indent].to_i.positive?
  save_options |= ::Nokogiri::XML::Node::SaveOptions::NO_DECLARATION if options[:no_declaration]

  node.to_xml(
    indent: options[:indent],
    encoding: options[:encoding],
    save_with: save_options
  )
end

.set_attribute(element, name, value) ⇒ Object



178
179
180
# File 'lib/moxml/adapter/nokogiri.rb', line 178

def set_attribute(element, name, value)
  element[name.to_s] = value.to_s
end

.set_cdata_content(node, content) ⇒ Object



240
241
242
# File 'lib/moxml/adapter/nokogiri.rb', line 240

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

.set_comment_content(node, content) ⇒ Object



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

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

.set_declaration_attribute(declaration, attr_name, value) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/moxml/adapter/nokogiri.rb', line 89

def set_declaration_attribute(declaration, attr_name, value)
  attrs = current_declaration_attributes(declaration)
  if value.nil?
    attrs.delete(attr_name)
  else
    attrs[attr_name] = value
  end

  declaration.native_content =
    attrs.map { |k, v| %(#{k}="#{v}") }.join(" ")
end

.set_namespace(element, ns) ⇒ Object



101
102
103
# File 'lib/moxml/adapter/nokogiri.rb', line 101

def set_namespace(element, ns)
  element.namespace = ns
end

.set_node_name(node, name) ⇒ Object



134
135
136
# File 'lib/moxml/adapter/nokogiri.rb', line 134

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

.set_processing_instruction_content(node, content) ⇒ Object



256
257
258
# File 'lib/moxml/adapter/nokogiri.rb', line 256

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

.set_root(doc, element) ⇒ Object



10
11
12
# File 'lib/moxml/adapter/nokogiri.rb', line 10

def set_root(doc, element)
  doc.root = element
end

.set_text_content(node, content) ⇒ Object



232
233
234
# File 'lib/moxml/adapter/nokogiri.rb', line 232

def set_text_content(node, content)
  node.native_content = content
end

.text_content(node) ⇒ Object



223
224
225
# File 'lib/moxml/adapter/nokogiri.rb', line 223

def text_content(node)
  node.content
end

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



272
273
274
275
276
# File 'lib/moxml/adapter/nokogiri.rb', line 272

def xpath(node, expression, namespaces = nil)
  node.xpath(expression, namespaces).to_a
rescue ::Nokogiri::XML::XPath::SyntaxError => e
  raise Moxml::XPathError, e.message
end