forked from sparklemotion/nokogiri
/
node_set.rb
150 lines (126 loc) · 4.76 KB
/
node_set.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
module Nokogiri
module XML
class NodeSet
attr_accessor :cstruct # :nodoc:
def dup # :nodoc:
dup = LibXML.xmlXPathNodeSetMerge(nil, self.cstruct)
NodeSet.wrap(dup, self.document)
end
def length # :nodoc:
cstruct.pointer.null? ? 0 : cstruct[:nodeNr]
end
def push(node) # :nodoc:
raise(ArgumentError, "node must be a Nokogiri::XML::Node") unless node.is_a?(XML::Node) || node.is_a?(XML::Namespace)
LibXML.xmlXPathNodeSetAdd(cstruct, node.cstruct)
self
end
def |(node_set) # :nodoc:
raise(ArgumentError, "node_set must be a Nokogiri::XML::NodeSet") unless node_set.is_a?(XML::NodeSet)
new_set_ptr = LibXML::xmlXPathNodeSetMerge(nil, self.cstruct)
new_set_ptr = LibXML::xmlXPathNodeSetMerge(new_set_ptr, node_set.cstruct)
NodeSet.wrap(new_set_ptr, self.document)
end
def -(node_set) # :nodoc:
raise(ArgumentError, "node_set must be a Nokogiri::XML::NodeSet") unless node_set.is_a?(XML::NodeSet)
new_set_ptr = LibXML.xmlXPathNodeSetMerge(nil, self.cstruct)
other_nodetab = node_set.cstruct.nodeTab
node_set.cstruct[:nodeNr].times do |j|
LibXML.xmlXPathNodeSetDel(new_set_ptr, other_nodetab[j])
end
NodeSet.wrap(new_set_ptr, self.document)
end
def delete(node) # :nodoc:
raise(ArgumentError, "node must be a Nokogiri::XML::Node") unless node.is_a?(XML::Node) || node.is_a?(XML::Namespace)
if LibXML.xmlXPathNodeSetContains(cstruct, node.cstruct) != 0
LibXML.xmlXPathNodeSetDel(cstruct, node.cstruct)
return node
end
return nil
end
def [](*args) # :nodoc:
raise(ArgumentError, "got #{args.length} arguments, expected 1 (or 2)") if args.length > 2
if args.length == 2
beg = args[0]
len = args[1]
beg += cstruct[:nodeNr] if beg < 0
return subseq(beg, len)
end
arg = args[0]
return subseq(arg.first, arg.last-arg.first+1) if arg.is_a?(Range)
index_at(arg)
end
alias_method :slice, :[]
def &(node_set) # :nodoc:
raise(ArgumentError, "node_set must be a Nokogiri::XML::NodeSet") unless node_set.is_a?(XML::NodeSet)
new_set_ptr = LibXML.xmlXPathIntersection(cstruct, node_set.cstruct)
NodeSet.wrap(new_set_ptr, self.document)
end
def include?(node) # :nodoc:
raise(ArgumentError, "node must be a Nokogiri::XML::Node") unless node.is_a?(XML::Node) || node.is_a?(XML::Namespace)
(LibXML.xmlXPathNodeSetContains(cstruct, node.cstruct) != 0) ? true : false
end
def to_a # :nodoc:
cstruct.nodeTab.collect do |node|
node_cstruct = LibXML::XmlNode.new(node)
if node_cstruct[:type] == XML::Node::NAMESPACE_DECL
Namespace.wrap(document.cstruct, node)
else
Node.wrap(node_cstruct)
end
end
end
def unlink # :nodoc:
return if cstruct[:nodeNr] == 0
nodetab = cstruct.nodeTab
cstruct[:nodeNr].times do |j|
node_cstruct = LibXML::XmlNode.new(nodetab[j])
if node_cstruct[:type] != XML::Node::NAMESPACE_DECL
node = Node.wrap(node_cstruct)
node.unlink
nodetab[j] = node.cstruct.pointer
end
end
cstruct.nodeTab = nodetab
self
end
def self.new document, list = [] # :nodoc:
set = NodeSet.wrap(LibXML.xmlXPathNodeSetCreate(nil), document)
set.document = document
list.each { |x| set << x }
yield set if block_given?
set
end
def self.wrap(ptr, document) # :nodoc:
set = allocate
set.cstruct = LibXML::XmlNodeSet.new(ptr)
if document
set.document = document
document.decorate(set)
end
set
end
private
def index_at(number) # :nodoc:
return nil if (number >= cstruct[:nodeNr] || number.abs > cstruct[:nodeNr])
number = number + cstruct[:nodeNr] if number < 0
node_ptr = cstruct.nodeAt(number)
node_cstruct = LibXML::XmlNode.new(node_ptr)
if node_cstruct[:type] == XML::Node::NAMESPACE_DECL
Namespace.wrap(document.cstruct, node_ptr)
else
Node.wrap(node_cstruct)
end
end
def subseq(beg, len) # :nodoc:
return nil if beg > cstruct[:nodeNr]
return nil if beg < 0 || len < 0
len = cstruct[:nodeNr] - beg if beg + len > cstruct[:nodeNr]
set = NodeSet.wrap(LibXML.xmlXPathNodeSetCreate(nil), self.document)
beg.upto(beg+len-1) do |j|
LibXML.xmlXPathNodeSetAddUnique(set.cstruct, cstruct.nodeAt(j));
end
set
end
end
end
end