xml-smart 0.3.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.
- data/AUTHORS +4 -0
- data/COPYING +504 -0
- data/README.rdoc +55 -0
- data/Rakefile +15 -0
- data/example/EXAMPLE.xml +18 -0
- data/example/xpath_visual.rb +54 -0
- data/lib/xml/XSDtoRNG.xsl +448 -0
- data/lib/xml/smart.rb +177 -0
- data/lib/xml/smart_dom.rb +118 -0
- data/lib/xml/smart_domattribute.rb +34 -0
- data/lib/xml/smart_domattributeset.rb +62 -0
- data/lib/xml/smart_domelement.rb +213 -0
- data/lib/xml/smart_domnamespace.rb +32 -0
- data/lib/xml/smart_domnamespaceset.rb +125 -0
- data/lib/xml/smart_domnodeset.rb +59 -0
- data/lib/xml/smart_domother.rb +16 -0
- data/lib/xml/smart_domtext.rb +25 -0
- data/lib/xml/smart_qname.rb +34 -0
- data/test/1.xml +1 -0
- data/test/2.xml +1 -0
- data/test/3.xml +1 -0
- data/test/EXAMPLE-NS.xml +18 -0
- data/test/EXAMPLE-NSE.xml +18 -0
- data/test/EXAMPLE.str.xml +6 -0
- data/test/EXAMPLE.str.xml.test +6 -0
- data/test/EXAMPLE.tmp.xml +4 -0
- data/test/EXAMPLE.tmp.xml.test +4 -0
- data/test/EXAMPLE.xml +17 -0
- data/test/HELLO-MORE.xml +1 -0
- data/test/HELLO.rng +9 -0
- data/test/HELLO.xml +8 -0
- data/test/HELLO.xsd +16 -0
- data/test/XSL_BASE.xml +17 -0
- data/test/XSL_BASE.xml.test +16 -0
- data/test/XSL_DOCUMENT.xml +48 -0
- data/test/concurrent.xml +1 -0
- data/test/smartrunner.rb +25 -0
- data/test/tc_add.rb +21 -0
- data/test/tc_basic.rb +108 -0
- data/test/tc_concurrent.rb +73 -0
- data/test/tc_copy.rb +41 -0
- data/test/tc_create.rb +32 -0
- data/test/tc_delete.rb +52 -0
- data/test/tc_move_elements.rb +24 -0
- data/test/tc_namespace_default.rb +70 -0
- data/test/tc_namespace_detailed.rb +44 -0
- data/test/tc_namespace_find.rb +22 -0
- data/test/tc_nested.rb +26 -0
- data/test/tc_qname.rb +30 -0
- data/test/tc_relaxng.rb +30 -0
- data/test/tc_set_or_replace.rb +57 -0
- data/test/tc_sort.rb +18 -0
- data/test/tc_string.rb +41 -0
- data/test/tc_todoc.rb +27 -0
- data/test/tc_write.rb +19 -0
- data/test/tc_xinclude.rb +26 -0
- data/test/tc_xmlschema.rb +30 -0
- data/test/tc_xpath.rb +16 -0
- data/test/tc_xpath_attrs.rb +24 -0
- data/test/tc_xpath_functions.rb +12 -0
- data/test/tc_xpath_root.rb +23 -0
- data/test/tc_xsl.rb +22 -0
- data/xml-smart.gemspec +26 -0
- metadata +201 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
def initialize(dom)
|
5
|
+
@dom = dom
|
6
|
+
@save_unformated = false
|
7
|
+
end
|
8
|
+
|
9
|
+
def ===(cls); self.is_a? cls; end
|
10
|
+
|
11
|
+
def root
|
12
|
+
Element.new(@dom.root)
|
13
|
+
end
|
14
|
+
def root=(nr)
|
15
|
+
@dom.root.replace(nr.instance_variable_get(:@element)) if nr.instance_of? Element
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(path)
|
19
|
+
Element.new(@dom.root).find(path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
@dom.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def namespaces
|
27
|
+
@dom.custom_namespace_prefixes.merge @dom.user_custom_namespace_prefixes
|
28
|
+
end
|
29
|
+
def register_namespace(a,b)
|
30
|
+
if a.respond_to?(:to_s) && b.respond_to?(:to_s) && !@dom.custom_namespace_prefixes.key?(a.to_s) && @dom.custom_namespace_prefixes.value?(b.to_s)
|
31
|
+
@dom.user_custom_namespace_prefixes[a.to_s] = b.to_s
|
32
|
+
@dom.ns_update
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
def unregister_namespace(a)
|
39
|
+
if a.respond_to?(:to_s) && @dom.user_custom_namespace_prefixes.key?(a.to_s)
|
40
|
+
@dom.user_custom_namespace_prefixes.delete(a.to_s)
|
41
|
+
@dom.ns_update
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def save_as(name)
|
49
|
+
raise Error, 'first parameter has to be a filename or filehandle' unless name.is_a?(String) || name.is_a?(IO)
|
50
|
+
begin
|
51
|
+
io = name.is_a?(String) ? ::Kernel::open(name,'w') : name
|
52
|
+
rescue
|
53
|
+
raise Error, "could not open #{name}"
|
54
|
+
end
|
55
|
+
ftext = if @save_unformated
|
56
|
+
@dom.root.serialize(:encoding => 'UTF-8', :save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION | Nokogiri::XML::Node::SaveOptions::AS_XML)
|
57
|
+
else
|
58
|
+
@dom.root.serialize(:encoding => 'UTF-8', :save_with => Nokogiri::XML::Node::SaveOptions::FORMAT | Nokogiri::XML::Node::SaveOptions::AS_XML)
|
59
|
+
end
|
60
|
+
io.write ftext
|
61
|
+
io.close
|
62
|
+
end
|
63
|
+
|
64
|
+
def save_unformated=(val); @save_unformated = (val.is_a?(TrueClass) ? true : false); end
|
65
|
+
def save_unformated?; @save_unformated; end
|
66
|
+
|
67
|
+
def xinclude!
|
68
|
+
Element.new(@dom.root).xinclude!
|
69
|
+
end
|
70
|
+
|
71
|
+
def self::smart_helper(node)
|
72
|
+
if node.instance_of? Nokogiri::XML::Element
|
73
|
+
Element.new(node)
|
74
|
+
elsif node.instance_of? Nokogiri::XML::Attr
|
75
|
+
Attribute.new(node)
|
76
|
+
elsif node.instance_of? Nokogiri::XML::NodeSet
|
77
|
+
NodeSet.new(node)
|
78
|
+
elsif node.instance_of?(String) || node.instance_of?(TrueClass) || node.instance_of?(FalseClass) || node.instance_of?(Float)
|
79
|
+
node
|
80
|
+
elsif node.instance_of? Nokogiri::XML::Text
|
81
|
+
Text.new(node)
|
82
|
+
elsif node.instance_of? Nokogiri::XML::Namespace
|
83
|
+
Namespace.new(node)
|
84
|
+
elsif node.instance_of? Nokogiri::XML::Document
|
85
|
+
Dom.new(node)
|
86
|
+
elsif node.nil?
|
87
|
+
nil
|
88
|
+
else
|
89
|
+
Other.new(node)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_against(doc,&errbl)
|
94
|
+
raise Error, 'first parameter has to XML::Smart::Dom document' unless doc.instance_of? Dom
|
95
|
+
res = if doc.root.namespaces.has_ns?("http://relaxng.org/ns/structure/1.0")
|
96
|
+
Nokogiri::XML::RelaxNG.from_document(doc.instance_variable_get(:@dom)).validate(@dom)
|
97
|
+
elsif doc.root.namespaces.has_ns?("http://www.w3.org/2001/XMLSchema")
|
98
|
+
tdoc = Nokogiri::XSLT.parse(File.read(File.expand_path(File.dirname(__FILE__) + '/XSDtoRNG.xsl')))
|
99
|
+
rdoc = tdoc.transform(doc.instance_variable_get(:@dom))
|
100
|
+
Nokogiri::XML::RelaxNG.from_document(rdoc).validate(@dom)
|
101
|
+
end
|
102
|
+
res.each { |err| errbl.call err } if block_given?
|
103
|
+
res.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
def transform_with(doc,params=nil)
|
107
|
+
raise Error, 'first parameter has to XML::Smart::Dom document' unless doc.instance_of? Dom
|
108
|
+
res = Nokogiri::XSLT::Stylesheet.parse_stylesheet_doc(doc.instance_variable_get(:@dom)).transform(@dom,params)
|
109
|
+
if res.children.length != 0 && res.children.first.class == Nokogiri::XML::Text
|
110
|
+
Text.new(res.children.first).text
|
111
|
+
else
|
112
|
+
Dom::smart_helper(res)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class Attribute
|
6
|
+
def initialize(attr)
|
7
|
+
@attr = attr
|
8
|
+
end
|
9
|
+
|
10
|
+
def ===(cls); self.is_a? cls; end
|
11
|
+
|
12
|
+
def to_s; @attr.content; end
|
13
|
+
def to_i; @attr.content.to_i; end
|
14
|
+
def to_f; @attr.content.to_f; end
|
15
|
+
|
16
|
+
def qname; QName.new @attr; end
|
17
|
+
def path; @attr.path; end
|
18
|
+
|
19
|
+
def value; @attr.content; end;
|
20
|
+
def value=(val); @attr.content = val; end;
|
21
|
+
|
22
|
+
def ==(other)
|
23
|
+
return false unless other
|
24
|
+
return false unless other.respond_to?(:unique_id)
|
25
|
+
unique_id == other.unique_id
|
26
|
+
end
|
27
|
+
def unique_id; @attr.pointer_id; end
|
28
|
+
|
29
|
+
def parent; Dom::smart_helper(@attr.parent); end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class AttributeSet
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(element)
|
9
|
+
@element = element
|
10
|
+
@set = @element.attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
def ===(cls); self.is_a? cls; end
|
14
|
+
|
15
|
+
def has_attr?(a); @set.has_key?(a) end
|
16
|
+
alias :include? :has_attr?
|
17
|
+
alias :attr? :has_attr?
|
18
|
+
alias :member? :has_attr?
|
19
|
+
|
20
|
+
def [](name,attr=false)
|
21
|
+
return nil unless @set[name]
|
22
|
+
if attr == false
|
23
|
+
@element[name]
|
24
|
+
else
|
25
|
+
Attribute.new(@set[name])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def []=(name,value);
|
29
|
+
@element[name] = value
|
30
|
+
end
|
31
|
+
|
32
|
+
def length; @set.length; end
|
33
|
+
def empty?; @set.empty?; end
|
34
|
+
def delete_all!; @set.each { |k,a| a.remove }; end
|
35
|
+
|
36
|
+
def each(&block)
|
37
|
+
@set.each do |k,node|
|
38
|
+
block.call Dom::smart_helper(node)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_at!(name)
|
43
|
+
tmp = @set[name]
|
44
|
+
if tmp === Nokogiri::XML::Attr
|
45
|
+
tmp.remove
|
46
|
+
true
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete_if!(&block)
|
53
|
+
@set.each do |k,node|
|
54
|
+
node.remove if block.call(Dom::smart_helper(node))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class Element
|
6
|
+
def initialize(element)
|
7
|
+
@element = element
|
8
|
+
end
|
9
|
+
|
10
|
+
def ===(cls); self.is_a? cls; end
|
11
|
+
|
12
|
+
def find(xpath)
|
13
|
+
Dom::smart_helper(@element.xpath_fast(xpath))
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_helper(attrs)
|
17
|
+
if attrs.length>0 && attrs[0].is_a?(String)
|
18
|
+
pfx = ''
|
19
|
+
ns = nil
|
20
|
+
if attrs[0].sub!(/([^:]+):/, '')
|
21
|
+
pfx = $1
|
22
|
+
if @element.document.user_custom_namespace_prefixes.has_key?(pfx)
|
23
|
+
@element.document.custom_namespace_prefixes.each do |k,v|
|
24
|
+
if @element.document.user_custom_namespace_prefixes[pfx] == v
|
25
|
+
ns = @element.document.user_custom_namespace_prefixes[pfx]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if ns.nil?
|
30
|
+
if @element.document.custom_namespace_prefixes.has_key?(pfx)
|
31
|
+
ns = @element.document.custom_namespace_prefixes[pfx]
|
32
|
+
else
|
33
|
+
raise Error, 'No valid namespace'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
tmp = Nokogiri::XML::Node.new attrs[0], @element.document
|
38
|
+
unless ns.nil?
|
39
|
+
@element.namespace_scopes.each do |nss|
|
40
|
+
tmp.namespace = nss if nss.href == ns
|
41
|
+
end
|
42
|
+
end
|
43
|
+
[1,2].each do |i|
|
44
|
+
if attrs.length > i
|
45
|
+
case attrs[i]
|
46
|
+
when Hash
|
47
|
+
attrs[i].each do |k,v|
|
48
|
+
if k.respond_to?(:to_s)
|
49
|
+
tmp[k.to_s] = v.respond_to?(:to_s) ? v.to_s : ''
|
50
|
+
else
|
51
|
+
raise Error, 'use something that has provides #to_s'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
tmp.content = attrs[i].respond_to?(:to_s) ? attrs[i].to_s : ''
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
return [tmp,false]
|
60
|
+
end
|
61
|
+
if attrs.length == 1 && attrs[0].is_a?(XML::Smart::Dom::Element)
|
62
|
+
ele = attrs[0].instance_variable_get(:@element)
|
63
|
+
same = ele.document.root.pointer_id == @element.document.root.pointer_id
|
64
|
+
return [same ? ele : ele.dup, !same]
|
65
|
+
end
|
66
|
+
if attrs.length == 1 && attrs[0].is_a?(XML::Smart::Dom::NodeSet)
|
67
|
+
nos = attrs[0].instance_variable_get(:@nodeset)
|
68
|
+
if nos.length > 0
|
69
|
+
same = nos.first.document.root.pointer_id == @element.document.root.pointer_id
|
70
|
+
if same
|
71
|
+
return [nos, false]
|
72
|
+
else
|
73
|
+
tnos = nos.map{|e|e.dup}
|
74
|
+
return [Nokogiri::XML::NodeSet.new(nos.first.document,tnos), true]
|
75
|
+
end
|
76
|
+
else
|
77
|
+
return [nos, false]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
if attrs.length == 2 && attrs[0].is_a?(XML::Smart::Dom::Element) && (attrs[1] == XML::Smart::COPY || attrs[1] == XML::Smart::MOVE)
|
81
|
+
ele = attrs[0].instance_variable_get(:@element)
|
82
|
+
same = ele.document.root.pointer_id == @element.document.root.pointer_id
|
83
|
+
return [attrs[1] == XML::Smart::COPY ? ele.dup : ele, !same]
|
84
|
+
end
|
85
|
+
if attrs.length == 2 && attrs[0].is_a?(XML::Smart::Dom::NodeSet) && (attrs[1] == XML::Smart::COPY || attrs[1] == XML::Smart::MOVE)
|
86
|
+
nos = attrs[0].instance_variable_get(:@nodeset)
|
87
|
+
if nos.length > 0
|
88
|
+
same = nos.first.document.root.pointer_id == @element.document.root.pointer_id
|
89
|
+
if attrs[1] == XML::Smart::COPY
|
90
|
+
tnos = nos.map{|e|e.dup}
|
91
|
+
nos = Nokogiri::XML::NodeSet.new(nos.first.document,tnos)
|
92
|
+
end
|
93
|
+
return [Nokogiri::XML::NodeSet.new(nos.first.document,tnos), true]
|
94
|
+
return [nos, !same]
|
95
|
+
else
|
96
|
+
return [nos, false]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return [nil, false]
|
100
|
+
end
|
101
|
+
private :add_helper
|
102
|
+
def add(*attrs)
|
103
|
+
tmp, update = add_helper(attrs)
|
104
|
+
res = Dom::smart_helper(@element.add_child tmp)
|
105
|
+
if update
|
106
|
+
@element.document.custom_namespace_prefixes_update
|
107
|
+
@element.document.ns_update
|
108
|
+
end
|
109
|
+
res
|
110
|
+
end
|
111
|
+
def add_before(*attrs)
|
112
|
+
tmp, update = add_helper(attrs)
|
113
|
+
res = Dom::smart_helper(@element.add_previous_sibling tmp)
|
114
|
+
if update
|
115
|
+
@element.document.custom_namespace_prefixes_update
|
116
|
+
@element.document.ns_update
|
117
|
+
end
|
118
|
+
res
|
119
|
+
end
|
120
|
+
def add_after(*attrs)
|
121
|
+
tmp, update = add_helper(attrs)
|
122
|
+
res = Dom::smart_helper(@element.add_next_sibling tmp)
|
123
|
+
if update
|
124
|
+
@element.document.custom_namespace_prefixes_update
|
125
|
+
@element.document.ns_update
|
126
|
+
end
|
127
|
+
res
|
128
|
+
end
|
129
|
+
|
130
|
+
def dump; @element.to_s; end
|
131
|
+
def to_s; @element.content; end
|
132
|
+
def to_i; @element.content.to_i; end
|
133
|
+
def to_f; @element.content.to_f; end
|
134
|
+
|
135
|
+
def namespace?; !@element.namespace.nil?; end
|
136
|
+
def namespace; namespace? ? Namespace.new(@element.namespace) : nil; end
|
137
|
+
def namespace=(n)
|
138
|
+
n = case n
|
139
|
+
when Namespace
|
140
|
+
n.prefix
|
141
|
+
when String
|
142
|
+
n
|
143
|
+
else
|
144
|
+
return
|
145
|
+
end
|
146
|
+
tmp = @element.document.custom_namespace_prefixes[n] || @element.document.user_custom_namespace_prefixes[n]
|
147
|
+
unless tmp.nil?
|
148
|
+
@element.namespace_scopes.each do |nss|
|
149
|
+
@element.namespace = nss if nss.href == tmp
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
def namespaces; NamespaceSet.new(self,@element); end
|
154
|
+
|
155
|
+
def xinclude!
|
156
|
+
@element.do_xinclude
|
157
|
+
@element.document.custom_namespace_prefixes_update
|
158
|
+
@element.document.ns_update
|
159
|
+
true
|
160
|
+
end
|
161
|
+
|
162
|
+
def replace_by(n)
|
163
|
+
case n
|
164
|
+
when Element; Element.new @element.replace(n.instance_variable_get(:@element))
|
165
|
+
when NodeSet; NodeSet.new @element.replace(n.instance_variable_get(:@nodeset))
|
166
|
+
else
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def qname; QName.new @element; end
|
172
|
+
def attributes; AttributeSet.new @element; end
|
173
|
+
|
174
|
+
def text; @element.xpath_fast("string(text())"); end
|
175
|
+
def text=(t); @element.content = t.to_s if t.respond_to? :to_s; end
|
176
|
+
|
177
|
+
def children; find('*'); end
|
178
|
+
def children?; find('*').length > 0 end
|
179
|
+
def parent
|
180
|
+
Dom::smart_helper(@element.parent)
|
181
|
+
end
|
182
|
+
def parent?; !@element.parent.nil?; end
|
183
|
+
|
184
|
+
def empty?; @element.blank?; end
|
185
|
+
def mixed?;
|
186
|
+
@element.xpath_fast('*').length > 0 && @element.xpath_fast("string(text())") != '';
|
187
|
+
end
|
188
|
+
def text_only?;
|
189
|
+
@element.xpath_fast('*').length == 0 && @element.xpath_fast("string(text())") != '';
|
190
|
+
end
|
191
|
+
def element_only?;
|
192
|
+
@element.xpath_fast('*').length > 0 && @element.xpath_fast("string(text())") == '';
|
193
|
+
end
|
194
|
+
|
195
|
+
def path; @element.path; end
|
196
|
+
|
197
|
+
def ==(other)
|
198
|
+
return false unless other
|
199
|
+
return false unless other.respond_to?(:unique_id)
|
200
|
+
unique_id == other.unique_id
|
201
|
+
end
|
202
|
+
def unique_id; @element.pointer_id; end
|
203
|
+
|
204
|
+
def to_doc
|
205
|
+
doc = Nokogiri::XML::Document.new
|
206
|
+
doc.root = @element
|
207
|
+
dom = Dom.new(doc)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class Namespace
|
6
|
+
def initialize(ns)
|
7
|
+
@ns = ns
|
8
|
+
end
|
9
|
+
|
10
|
+
def ===(cls); self.is_a? cls; end
|
11
|
+
|
12
|
+
def href; @ns.href; end
|
13
|
+
alias :to_s :href
|
14
|
+
|
15
|
+
def prefix
|
16
|
+
if @ns.prefix
|
17
|
+
@ns.prefix
|
18
|
+
else
|
19
|
+
@ns.document.custom_namespace_prefixes.find{|k,v| v == @ns.href}[0]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(other)
|
24
|
+
return false unless other
|
25
|
+
return false unless other.respond_to?(:to_s)
|
26
|
+
to_s == other.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class NamespaceSet
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(parent,node)
|
9
|
+
@parent = parent
|
10
|
+
@node = node
|
11
|
+
end
|
12
|
+
|
13
|
+
def ===(cls); self.is_a? cls; end
|
14
|
+
|
15
|
+
def has_ns?(a); @node.namespace_definitions.one?{|e| e.href == a || e.prefix == a}; end
|
16
|
+
alias :include? :has_ns?
|
17
|
+
alias :ns? :has_ns?
|
18
|
+
alias :member? :has_ns?
|
19
|
+
|
20
|
+
def [](name)
|
21
|
+
if name.nil? || name.respond_to?(:to_s)
|
22
|
+
name = name.to_s unless name.nil?
|
23
|
+
name = nil if name =~ /^xmlns\d*$/
|
24
|
+
nd = @node.namespace_definitions.find{|n| n.prefix == name}
|
25
|
+
(name.respond_to?(:to_s) || name.nil?) && nd ? Namespace.new(nd) : nil;
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def []=(name,value)
|
29
|
+
self.add(name,value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def add(name,value)
|
33
|
+
if (name.respond_to?(:to_s) || name.nil?) && value.respond_to?(:to_s)
|
34
|
+
nnod = Nokogiri::XML::Node.new(@node.name,@node.document)
|
35
|
+
nnew = Element.new(nnod)
|
36
|
+
nold = Element.new(@node)
|
37
|
+
nold.attributes.each do |attr|
|
38
|
+
nnew.attributes[attr.qname.name] = attr.value
|
39
|
+
end
|
40
|
+
ns = nnod.add_namespace_definition(name,value)
|
41
|
+
@node.namespace_definitions.each do |ns|
|
42
|
+
nnod.add_namespace_definition(ns.prefix,ns.href)
|
43
|
+
end
|
44
|
+
nnew.add(nold.children)
|
45
|
+
nold.replace_by(nnew)
|
46
|
+
@node = nnod
|
47
|
+
@parent.instance_variable_set(:@element,@node)
|
48
|
+
@node.document.custom_namespace_prefixes_update
|
49
|
+
@node.document.ns_update
|
50
|
+
Namespace.new(ns)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def length; @node.namespace_definitions.length; end
|
55
|
+
def empty?; @node.namespace_definitions.empty?; end
|
56
|
+
def delete_all!
|
57
|
+
nnod = Nokogiri::XML::Node.new(@node.name,@node.document)
|
58
|
+
nnew = Element.new(nnod)
|
59
|
+
nold = Element.new(@node)
|
60
|
+
nold.attributes.each do |attr|
|
61
|
+
nnew.attributes[attr.qname.name] = attr.value
|
62
|
+
end
|
63
|
+
nnew.add(nold.children)
|
64
|
+
nold.replace_by(nnew)
|
65
|
+
@node = nnod
|
66
|
+
@parent.instance_variable_set(:@element,@node)
|
67
|
+
@node.document.custom_namespace_prefixes_update
|
68
|
+
@node.document.ns_update
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def each(&block)
|
73
|
+
@node.namespace_definitions.each do |ns|
|
74
|
+
block.call Namespace.new(ns)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete_at(name)
|
79
|
+
if (name.respond_to?(:to_s) || name.nil?)
|
80
|
+
return false unless @node.namespace_definitions.one?{|e| e.prefix == name}
|
81
|
+
|
82
|
+
nnod = Nokogiri::XML::Node.new(@node.name,@node.document)
|
83
|
+
nnew = Element.new(nnod)
|
84
|
+
nold = Element.new(@node)
|
85
|
+
nold.attributes.each do |attr|
|
86
|
+
nnew.attributes[attr.qname.name] = attr.value
|
87
|
+
end
|
88
|
+
@node.namespace_definitions.each do |ns|
|
89
|
+
nnod.add_namespace_definition(ns.prefix,ns.href) unless ns.prefix == name
|
90
|
+
end
|
91
|
+
nnew.add(nold.children)
|
92
|
+
nold.replace_by(nnew)
|
93
|
+
@node = nnod
|
94
|
+
@parent.instance_variable_set(:@element,@node)
|
95
|
+
@node.document.custom_namespace_prefixes_update
|
96
|
+
@node.document.ns_update
|
97
|
+
true
|
98
|
+
else
|
99
|
+
false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete_if(&block)
|
104
|
+
nnod = Nokogiri::XML::Node.new(@node.name,@node.document)
|
105
|
+
nnew = Element.new(nnod)
|
106
|
+
nold = Element.new(@node)
|
107
|
+
nold.attributes.each do |attr|
|
108
|
+
nnew.attributes[attr.qname.name] = attr.value
|
109
|
+
end
|
110
|
+
@node.namespace_definitions.each do |ns|
|
111
|
+
nnod.add_namespace_definition(ns.prefix,ns.href) unless block.call(Dom::smart_helper(ns))
|
112
|
+
end
|
113
|
+
nnew.add(nold.children)
|
114
|
+
nold.replace_by(nnew)
|
115
|
+
@node = nnod
|
116
|
+
@parent.instance_variable_set(:@element,@node)
|
117
|
+
@node.document.custom_namespace_prefixes_update
|
118
|
+
@node.document.ns_update
|
119
|
+
self
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class NodeSet
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(nodeset)
|
9
|
+
@nodeset = nodeset
|
10
|
+
end
|
11
|
+
|
12
|
+
def ===(cls); self.is_a? cls; end
|
13
|
+
|
14
|
+
def first; Dom::smart_helper(@nodeset.first); end
|
15
|
+
def last; Dom::smart_helper(@nodeset.last); end
|
16
|
+
def at(*a); Dom::smart_helper(@nodeset[*a]); end
|
17
|
+
def [](*a); Dom::smart_helper(@nodeset[*a]); end
|
18
|
+
|
19
|
+
def length; @nodeset.length; end
|
20
|
+
def empty?; @nodeset.empty?; end
|
21
|
+
def delete_all!; @nodeset.remove; @nodeset.to_a.each { |n| @nodeset.delete(n) }; true end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
@nodeset.each do |node|
|
25
|
+
block.call Dom::smart_helper(node)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_at(*a)
|
30
|
+
tmp = @nodeset[*a]
|
31
|
+
case tmp
|
32
|
+
when Nokogiri::XML::NodeSet
|
33
|
+
tmp.each { |node| @nodeset.delete(node.remove) }
|
34
|
+
true
|
35
|
+
when Nokogiri::XML::Node
|
36
|
+
@nodeset.delete(tmp.remove)
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete_if(&block)
|
44
|
+
tmp = []
|
45
|
+
@nodeset.each do |node|
|
46
|
+
if block.call(Dom::smart_helper(node))
|
47
|
+
tmp << node.remove
|
48
|
+
end
|
49
|
+
end
|
50
|
+
tmp.each { |t| @nodeset.delete(t) }
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module XML
|
2
|
+
module Smart
|
3
|
+
class Dom
|
4
|
+
|
5
|
+
class Text
|
6
|
+
def initialize(text); @text = text; end
|
7
|
+
|
8
|
+
def ===(cls); self.is_a? cls; end
|
9
|
+
|
10
|
+
def dump; to_s; end
|
11
|
+
def to_s; @text.content.to_s; end
|
12
|
+
def to_f; @text.content.to_f; end
|
13
|
+
def to_i; @text.content.to_i; end
|
14
|
+
|
15
|
+
def text; @text.content; end
|
16
|
+
def text=(t); @text.content = t.to_s if t.respond_to? :to_s; end
|
17
|
+
|
18
|
+
def parent; Node.new(@text.parent); end
|
19
|
+
|
20
|
+
def path; @text.path; end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|