moxml 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +27 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/Gemfile +12 -0
- data/README.adoc +770 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/lib/moxml/adapter.rb +175 -0
- data/lib/moxml/attribute.rb +30 -0
- data/lib/moxml/cdata.rb +39 -0
- data/lib/moxml/comment.rb +35 -0
- data/lib/moxml/config.rb +23 -0
- data/lib/moxml/declaration.rb +50 -0
- data/lib/moxml/document.rb +99 -0
- data/lib/moxml/element.rb +145 -0
- data/lib/moxml/error_handler.rb +77 -0
- data/lib/moxml/errors.rb +169 -0
- data/lib/moxml/namespace.rb +54 -0
- data/lib/moxml/node.rb +113 -0
- data/lib/moxml/node_set.rb +268 -0
- data/lib/moxml/processing_instruction.rb +44 -0
- data/lib/moxml/text.rb +39 -0
- data/lib/moxml/version.rb +5 -0
- data/lib/moxml.rb +44 -0
- data/moxml.gemspec +34 -0
- data/sig/moxml.rbs +4 -0
- metadata +74 -0
data/lib/moxml/errors.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# lib/moxml/errors.rb
|
2
|
+
module Moxml
|
3
|
+
# Base error class for all Moxml errors
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
# Parsing related errors
|
7
|
+
class ParseError < Error
|
8
|
+
attr_reader :line, :column, :source
|
9
|
+
|
10
|
+
def initialize(message, line: nil, column: nil, source: nil)
|
11
|
+
@line = line
|
12
|
+
@column = column
|
13
|
+
@source = source
|
14
|
+
super(build_message(message))
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_message(message)
|
20
|
+
parts = [message]
|
21
|
+
parts << "Line: #{line}" if line
|
22
|
+
parts << "Column: #{column}" if column
|
23
|
+
parts << "\nSource: #{source}" if source
|
24
|
+
parts.join(" | ")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Validation errors
|
29
|
+
class ValidationError < Error; end
|
30
|
+
class DTDValidationError < ValidationError; end
|
31
|
+
class SchemaValidationError < ValidationError; end
|
32
|
+
class NamespaceError < ValidationError; end
|
33
|
+
|
34
|
+
# Structure errors
|
35
|
+
class MalformedXMLError < ParseError; end
|
36
|
+
class UnbalancedTagError < ParseError; end
|
37
|
+
class UndefinedEntityError < ParseError; end
|
38
|
+
class DuplicateAttributeError < ParseError; end
|
39
|
+
|
40
|
+
# Encoding errors
|
41
|
+
class EncodingError < Error
|
42
|
+
attr_reader :encoding
|
43
|
+
|
44
|
+
def initialize(message, encoding)
|
45
|
+
@encoding = encoding
|
46
|
+
super("#{message} (Encoding: #{encoding})")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Security related errors
|
51
|
+
class SecurityError < Error; end
|
52
|
+
class MaxDepthExceededError < SecurityError; end
|
53
|
+
class MaxAttributesExceededError < SecurityError; end
|
54
|
+
class MaxNameLengthExceededError < SecurityError; end
|
55
|
+
class EntityExpansionError < SecurityError; end
|
56
|
+
|
57
|
+
# Backend errors
|
58
|
+
class BackendError < Error
|
59
|
+
attr_reader :backend
|
60
|
+
|
61
|
+
def initialize(message, backend)
|
62
|
+
@backend = backend
|
63
|
+
super("#{message} (Backend: #{backend})")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class BackendNotFoundError < BackendError; end
|
68
|
+
class BackendConfigurationError < BackendError; end
|
69
|
+
|
70
|
+
# Node manipulation errors
|
71
|
+
class NodeError < Error
|
72
|
+
attr_reader :node
|
73
|
+
|
74
|
+
def initialize(message, node)
|
75
|
+
@node = node
|
76
|
+
super("#{message} (Node: #{node.class})")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class InvalidNodeTypeError < NodeError; end
|
81
|
+
class InvalidOperationError < NodeError; end
|
82
|
+
class NodeNotFoundError < NodeError; end
|
83
|
+
|
84
|
+
# Visitor pattern errors
|
85
|
+
class VisitorError < Error; end
|
86
|
+
|
87
|
+
class InvalidSelectorError < VisitorError
|
88
|
+
attr_reader :selector
|
89
|
+
|
90
|
+
def initialize(message, selector)
|
91
|
+
@selector = selector
|
92
|
+
super("#{message} (Selector: #{selector})")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class VisitorMethodError < VisitorError
|
97
|
+
attr_reader :method_name
|
98
|
+
|
99
|
+
def initialize(message, method_name)
|
100
|
+
@method_name = method_name
|
101
|
+
super("#{message} (Method: #{method_name})")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Serialization errors
|
106
|
+
class SerializationError < Error; end
|
107
|
+
|
108
|
+
class InvalidOptionsError < SerializationError
|
109
|
+
attr_reader :options
|
110
|
+
|
111
|
+
def initialize(message, options)
|
112
|
+
@options = options
|
113
|
+
super("#{message} (Options: #{options})")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# IO errors
|
118
|
+
class IOError < Error
|
119
|
+
attr_reader :path
|
120
|
+
|
121
|
+
def initialize(message, path)
|
122
|
+
@path = path
|
123
|
+
super("#{message} (Path: #{path})")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class FileNotFoundError < IOError; end
|
128
|
+
class WriteError < IOError; end
|
129
|
+
|
130
|
+
# Memory errors
|
131
|
+
class MemoryError < Error
|
132
|
+
attr_reader :size
|
133
|
+
|
134
|
+
def initialize(message, size)
|
135
|
+
@size = size
|
136
|
+
super("#{message} (Size: #{size} bytes)")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class DocumentTooLargeError < MemoryError; end
|
141
|
+
|
142
|
+
# CDATA related errors
|
143
|
+
class CDATAError < Error; end
|
144
|
+
class NestedCDATAError < CDATAError; end
|
145
|
+
class InvalidCDATAContentError < CDATAError; end
|
146
|
+
|
147
|
+
# Namespace related errors
|
148
|
+
class NamespaceDeclarationError < Error
|
149
|
+
attr_reader :prefix, :uri
|
150
|
+
|
151
|
+
def initialize(message, prefix, uri)
|
152
|
+
@prefix = prefix
|
153
|
+
@uri = uri
|
154
|
+
super("#{message} (Prefix: #{prefix}, URI: #{uri})")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# XPath related errors
|
159
|
+
class XPathError < Error
|
160
|
+
attr_reader :expression
|
161
|
+
|
162
|
+
def initialize(message, expression)
|
163
|
+
@expression = expression
|
164
|
+
super("#{message} (Expression: #{expression})")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class InvalidXPathError < XPathError; end
|
169
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Moxml
|
2
|
+
class Namespace < Node
|
3
|
+
def initialize(prefix_or_native = nil, uri = nil)
|
4
|
+
case prefix_or_native
|
5
|
+
when String
|
6
|
+
super(adapter.create_namespace(nil, prefix_or_native, uri))
|
7
|
+
else
|
8
|
+
super(prefix_or_native)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def prefix
|
13
|
+
adapter.namespace_prefix(native)
|
14
|
+
end
|
15
|
+
|
16
|
+
def prefix=(new_prefix)
|
17
|
+
adapter.set_namespace_prefix(native, new_prefix)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def uri
|
22
|
+
adapter.namespace_uri(native)
|
23
|
+
end
|
24
|
+
|
25
|
+
def uri=(new_uri)
|
26
|
+
adapter.set_namespace_uri(native, new_uri)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def blank?
|
31
|
+
uri.nil? || uri.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def namespace?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
other.is_a?(Namespace) &&
|
40
|
+
other.prefix == prefix &&
|
41
|
+
other.uri == uri
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
prefix ? "xmlns:#{prefix}='#{uri}'" : "xmlns='#{uri}'"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def create_native_node
|
51
|
+
adapter.create_namespace(nil, "", "")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/moxml/node.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
module Moxml
|
2
|
+
class Node
|
3
|
+
attr_reader :native
|
4
|
+
|
5
|
+
def initialize(native_node = nil)
|
6
|
+
@native = native_node || create_native_node
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.wrap(native_node)
|
10
|
+
return nil if native_node.nil?
|
11
|
+
|
12
|
+
klass = case Moxml.adapter.node_type(native_node)
|
13
|
+
when :element then Element
|
14
|
+
when :text then Text
|
15
|
+
when :cdata then Cdata
|
16
|
+
when :comment then Comment
|
17
|
+
when :processing_instruction then ProcessingInstruction
|
18
|
+
when :document then Document
|
19
|
+
when :attribute then Attribute
|
20
|
+
when :namespace then Namespace
|
21
|
+
else
|
22
|
+
raise Error, "Unknown node type: #{native_node.class}"
|
23
|
+
end
|
24
|
+
|
25
|
+
klass.new(native_node)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parent
|
29
|
+
wrap_node(adapter.parent(native))
|
30
|
+
end
|
31
|
+
|
32
|
+
def children
|
33
|
+
NodeSet.new(adapter.children(native))
|
34
|
+
end
|
35
|
+
|
36
|
+
def next_sibling
|
37
|
+
wrap_node(adapter.next_sibling(native))
|
38
|
+
end
|
39
|
+
|
40
|
+
def previous_sibling
|
41
|
+
wrap_node(adapter.previous_sibling(native))
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove
|
45
|
+
adapter.remove(native)
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def replace(node)
|
50
|
+
adapter.replace(native, node.native)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_previous_sibling(node)
|
55
|
+
adapter.add_previous_sibling(native, node.native)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_next_sibling(node)
|
60
|
+
adapter.add_next_sibling(native, node.native)
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def text
|
65
|
+
adapter.text_content(native)
|
66
|
+
end
|
67
|
+
|
68
|
+
def text=(content)
|
69
|
+
adapter.set_text_content(native, content)
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def inner_html
|
74
|
+
adapter.inner_html(native)
|
75
|
+
end
|
76
|
+
|
77
|
+
def inner_html=(html)
|
78
|
+
adapter.set_inner_html(native, html)
|
79
|
+
end
|
80
|
+
|
81
|
+
def outer_html
|
82
|
+
adapter.outer_html(native)
|
83
|
+
end
|
84
|
+
|
85
|
+
def path
|
86
|
+
adapter.path(native)
|
87
|
+
end
|
88
|
+
|
89
|
+
def line
|
90
|
+
adapter.line(native)
|
91
|
+
end
|
92
|
+
|
93
|
+
def column
|
94
|
+
adapter.column(native)
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def wrap_node(native_node)
|
100
|
+
self.class.wrap(native_node)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def adapter
|
106
|
+
Moxml.adapter
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_native_node
|
110
|
+
raise NotImplementedError, "Subclasses must implement create_native_node"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
# lib/moxml/node_set.rb
|
2
|
+
module Moxml
|
3
|
+
class NodeSet
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :native_nodes
|
7
|
+
|
8
|
+
def initialize(native_nodes = [])
|
9
|
+
@native_nodes = Array(native_nodes)
|
10
|
+
end
|
11
|
+
|
12
|
+
def each
|
13
|
+
return enum_for(:each) unless block_given?
|
14
|
+
native_nodes.each { |node| yield Node.wrap(node) }
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](index)
|
19
|
+
case index
|
20
|
+
when Integer
|
21
|
+
Node.wrap(native_nodes[index])
|
22
|
+
when Range
|
23
|
+
NodeSet.new(native_nodes[index])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def first
|
28
|
+
Node.wrap(native_nodes.first)
|
29
|
+
end
|
30
|
+
|
31
|
+
def last
|
32
|
+
Node.wrap(native_nodes.last)
|
33
|
+
end
|
34
|
+
|
35
|
+
def empty?
|
36
|
+
native_nodes.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def size
|
40
|
+
native_nodes.size
|
41
|
+
end
|
42
|
+
|
43
|
+
alias length size
|
44
|
+
|
45
|
+
def to_a
|
46
|
+
map { |node| node }
|
47
|
+
end
|
48
|
+
|
49
|
+
def filter(selector)
|
50
|
+
NodeSet.new(
|
51
|
+
native_nodes.select { |node| Moxml.adapter.matches?(node, selector) }
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def remove
|
56
|
+
each(&:remove)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def text
|
61
|
+
map(&:text).join
|
62
|
+
end
|
63
|
+
|
64
|
+
def inner_html
|
65
|
+
map(&:inner_html).join
|
66
|
+
end
|
67
|
+
|
68
|
+
def wrap(html_or_element)
|
69
|
+
each do |node|
|
70
|
+
wrapper = case html_or_element
|
71
|
+
when String
|
72
|
+
Document.parse("<div>#{html_or_element}</div>").root.children.first
|
73
|
+
when Element
|
74
|
+
html_or_element.dup
|
75
|
+
else
|
76
|
+
raise ArgumentError, "Expected String or Element"
|
77
|
+
end
|
78
|
+
|
79
|
+
node.add_previous_sibling(wrapper)
|
80
|
+
wrapper.add_child(node)
|
81
|
+
end
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_class(names)
|
86
|
+
each do |node|
|
87
|
+
next unless node.is_a?(Element)
|
88
|
+
current = (node["class"] || "").split(/\s+/)
|
89
|
+
new_classes = names.is_a?(Array) ? names : names.split(/\s+/)
|
90
|
+
node["class"] = (current + new_classes).uniq.join(" ")
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def remove_class(names)
|
96
|
+
each do |node|
|
97
|
+
next unless node.is_a?(Element)
|
98
|
+
current = (node["class"] || "").split(/\s+/)
|
99
|
+
remove_classes = names.is_a?(Array) ? names : names.split(/\s+/)
|
100
|
+
node["class"] = (current - remove_classes).join(" ")
|
101
|
+
end
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
def attr(name, value = nil)
|
106
|
+
if value.nil?
|
107
|
+
first&.[](name)
|
108
|
+
else
|
109
|
+
each { |node| node[name] = value if node.is_a?(Element) }
|
110
|
+
self
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Collection operations
|
115
|
+
def +(other)
|
116
|
+
NodeSet.new(native_nodes + other.native_nodes)
|
117
|
+
end
|
118
|
+
|
119
|
+
def -(other)
|
120
|
+
NodeSet.new(native_nodes - other.native_nodes)
|
121
|
+
end
|
122
|
+
|
123
|
+
def &(other)
|
124
|
+
NodeSet.new(native_nodes & other.native_nodes)
|
125
|
+
end
|
126
|
+
|
127
|
+
def |(other)
|
128
|
+
NodeSet.new(native_nodes | other.native_nodes)
|
129
|
+
end
|
130
|
+
|
131
|
+
def uniq
|
132
|
+
NodeSet.new(native_nodes.uniq)
|
133
|
+
end
|
134
|
+
|
135
|
+
def reverse
|
136
|
+
NodeSet.new(native_nodes.reverse)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Search and filtering
|
140
|
+
def find_by_id(id)
|
141
|
+
detect { |node| node.is_a?(Element) && node["id"] == id }
|
142
|
+
end
|
143
|
+
|
144
|
+
def find_by_class(class_name)
|
145
|
+
select { |node| node.is_a?(Element) && (node["class"] || "").split(/\s+/).include?(class_name) }
|
146
|
+
end
|
147
|
+
|
148
|
+
def find_by_attribute(name, value = nil)
|
149
|
+
select do |node|
|
150
|
+
next unless node.is_a?(Element)
|
151
|
+
if value.nil?
|
152
|
+
node.attributes.key?(name)
|
153
|
+
else
|
154
|
+
node[name] == value
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def of_type(type)
|
160
|
+
select { |node| node.is_a?(type) }
|
161
|
+
end
|
162
|
+
|
163
|
+
# DOM Manipulation
|
164
|
+
def before(node_or_nodes)
|
165
|
+
each { |node| node.add_previous_sibling(node_or_nodes) }
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
def after(node_or_nodes)
|
170
|
+
each { |node| node.add_next_sibling(node_or_nodes) }
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
def replace_with(node_or_nodes)
|
175
|
+
each { |node| node.replace(node_or_nodes) }
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
def wrap_all(wrapper)
|
180
|
+
return self if empty?
|
181
|
+
|
182
|
+
wrapper_node = case wrapper
|
183
|
+
when String
|
184
|
+
Document.parse(wrapper).root
|
185
|
+
when Element
|
186
|
+
wrapper
|
187
|
+
else
|
188
|
+
raise ArgumentError, "Expected String or Element"
|
189
|
+
end
|
190
|
+
|
191
|
+
first.add_previous_sibling(wrapper_node)
|
192
|
+
wrapper_node.add_child(self)
|
193
|
+
self
|
194
|
+
end
|
195
|
+
|
196
|
+
# Content manipulation
|
197
|
+
def inner_text=(text)
|
198
|
+
each { |node| node.inner_text = text }
|
199
|
+
self
|
200
|
+
end
|
201
|
+
|
202
|
+
def inner_html=(html)
|
203
|
+
each { |node| node.inner_html = html }
|
204
|
+
self
|
205
|
+
end
|
206
|
+
|
207
|
+
# Attribute operations
|
208
|
+
def toggle_class(names)
|
209
|
+
names = names.split(/\s+/) if names.is_a?(String)
|
210
|
+
each do |node|
|
211
|
+
next unless node.is_a?(Element)
|
212
|
+
current = (node["class"] || "").split(/\s+/)
|
213
|
+
names.each do |name|
|
214
|
+
if current.include?(name)
|
215
|
+
current.delete(name)
|
216
|
+
else
|
217
|
+
current << name
|
218
|
+
end
|
219
|
+
end
|
220
|
+
node["class"] = current.uniq.join(" ")
|
221
|
+
end
|
222
|
+
self
|
223
|
+
end
|
224
|
+
|
225
|
+
def has_class?(name)
|
226
|
+
any? { |node| node.is_a?(Element) && (node["class"] || "").split(/\s+/).include?(name) }
|
227
|
+
end
|
228
|
+
|
229
|
+
def remove_attr(*attrs)
|
230
|
+
each do |node|
|
231
|
+
next unless node.is_a?(Element)
|
232
|
+
attrs.each { |attr| node.remove_attribute(attr) }
|
233
|
+
end
|
234
|
+
self
|
235
|
+
end
|
236
|
+
|
237
|
+
# Position and hierarchy
|
238
|
+
def parents
|
239
|
+
NodeSet.new(
|
240
|
+
map { |node| node.parent }.compact.uniq
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
def children
|
245
|
+
NodeSet.new(
|
246
|
+
flat_map { |node| node.children.to_a }
|
247
|
+
)
|
248
|
+
end
|
249
|
+
|
250
|
+
def siblings
|
251
|
+
NodeSet.new(
|
252
|
+
flat_map { |node| node.parent ? node.parent.children.reject { |sibling| sibling == node } : [] }
|
253
|
+
).uniq
|
254
|
+
end
|
255
|
+
|
256
|
+
def next
|
257
|
+
NodeSet.new(
|
258
|
+
map { |node| node.next_sibling }.compact
|
259
|
+
)
|
260
|
+
end
|
261
|
+
|
262
|
+
def previous
|
263
|
+
NodeSet.new(
|
264
|
+
map { |node| node.previous_sibling }.compact
|
265
|
+
)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Moxml
|
2
|
+
class ProcessingInstruction < Node
|
3
|
+
def initialize(target_or_native = nil, content = nil)
|
4
|
+
case target_or_native
|
5
|
+
when String
|
6
|
+
super(adapter.create_processing_instruction(nil, target_or_native, content))
|
7
|
+
else
|
8
|
+
super(target_or_native)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def target
|
13
|
+
adapter.processing_instruction_target(native)
|
14
|
+
end
|
15
|
+
|
16
|
+
def target=(new_target)
|
17
|
+
adapter.set_processing_instruction_target(native, new_target)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def content
|
22
|
+
adapter.processing_instruction_content(native)
|
23
|
+
end
|
24
|
+
|
25
|
+
def content=(new_content)
|
26
|
+
adapter.set_processing_instruction_content(native, new_content)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def blank?
|
31
|
+
content.strip.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def processing_instruction?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def create_native_node
|
41
|
+
adapter.create_processing_instruction(nil, "", "")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/moxml/text.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Moxml
|
2
|
+
class Text < Node
|
3
|
+
def initialize(content_or_native = nil)
|
4
|
+
case content_or_native
|
5
|
+
when String
|
6
|
+
super(adapter.create_text(nil, content_or_native))
|
7
|
+
else
|
8
|
+
super(content_or_native)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def content
|
13
|
+
adapter.text_content(native)
|
14
|
+
end
|
15
|
+
|
16
|
+
def content=(text)
|
17
|
+
adapter.set_text_content(native, text)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def blank?
|
22
|
+
content.strip.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def cdata?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def text?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_native_node
|
36
|
+
adapter.create_text(nil, "")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|