1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package groovy.util.slurpersupport;
19
20 import groovy.lang.Buildable;
21 import groovy.lang.Closure;
22 import groovy.lang.DelegatingMetaClass;
23 import groovy.lang.GroovyObjectSupport;
24 import groovy.lang.MetaClass;
25 import groovy.lang.Writable;
26
27 import java.math.BigDecimal;
28 import java.math.BigInteger;
29 import java.net.MalformedURLException;
30 import java.net.URI;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.LinkedList;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Stack;
39
40 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
41
42
43 /***
44 * @author John Wilson
45 *
46 */
47
48 public abstract class GPathResult extends GroovyObjectSupport implements Writable, Buildable {
49 protected final GPathResult parent;
50 protected final String name;
51 protected final String namespacePrefix;
52 protected final Map namespaceMap = new HashMap();
53 protected final Map namespaceTagHints;
54
55 /***
56 * @param parent
57 * @param name
58 */
59 public GPathResult(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
60 if (parent == null) {
61
62 this.parent = this;
63 this.namespaceMap.put("xml", "http://www.w3.org/XML/1998/namespace"); // The XML namespace is always defined
64 } else {
65 this.parent = parent;
66 this.namespaceMap.putAll(parent.namespaceMap);
67 }
68 this.name = name;
69 this.namespacePrefix = namespacePrefix;
70 this.namespaceTagHints = namespaceTagHints;
71
72 setMetaClass(getMetaClass());
73 }
74
75
76
77
78 public void setMetaClass(final MetaClass metaClass) {
79 final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
80
81
82
83 public Object getAttribute(Object object, String attribute) {
84 return GPathResult.this.getProperty("@" + attribute);
85 }
86 };
87
88 super.setMetaClass(newMetaClass);
89 }
90
91 public Object getProperty(final String property) {
92 if ("..".equals(property)) {
93 return parent();
94 } else if ("*".equals(property)){
95 return children();
96 } else if ("**".equals(property)){
97 return depthFirst();
98 } else if (property.startsWith("@")) {
99 if (property.indexOf(":") != -1) {
100 final int i = property.indexOf(":");
101
102 return new Attributes(this, "@" + property.substring(i + 1), property.substring(1, i), this.namespaceTagHints);
103 } else {
104 return new Attributes(this, property, this.namespaceTagHints);
105 }
106 } else {
107 if (property.indexOf(":") != -1) {
108 final int i = property.indexOf(":");
109
110 return new NodeChildren(this, property.substring(i + 1), property.substring(0, i), this.namespaceTagHints);
111 } else {
112 return new NodeChildren(this, property, this.namespaceTagHints);
113 }
114 }
115 }
116
117 public String name() {
118 return this.name;
119 }
120
121 public GPathResult parent() {
122 return this.parent;
123 }
124
125 public GPathResult children() {
126 return new NodeChildren(this, this.namespaceTagHints);
127 }
128
129 public String toString() {
130 return text();
131 }
132
133 public Integer toInteger() {
134 return DefaultGroovyMethods.toInteger(text());
135 }
136
137 public Long toLong() {
138 return DefaultGroovyMethods.toLong(text());
139 }
140
141 public Float toFloat() {
142 return DefaultGroovyMethods.toFloat(text());
143 }
144
145 public Double toDouble() {
146 return DefaultGroovyMethods.toDouble(text());
147 }
148
149 public BigDecimal toBigDecimal() {
150 return DefaultGroovyMethods.toBigDecimal(text());
151 }
152
153 public BigInteger toBigInteger() {
154 return DefaultGroovyMethods.toBigInteger(text());
155 }
156
157 public URL toURL() throws MalformedURLException {
158 return DefaultGroovyMethods.toURL(text());
159 }
160
161 public URI toURI() throws URISyntaxException {
162 return DefaultGroovyMethods.toURI(text());
163 }
164
165 public Boolean toBoolean() {
166 return DefaultGroovyMethods.toBoolean(text());
167 }
168
169 public GPathResult declareNamespace(final Map newNamespaceMapping) {
170 this.namespaceMap.putAll(newNamespaceMapping);
171
172 return this;
173 }
174
175
176
177
178 public boolean equals(Object obj) {
179 return text().equals(obj.toString());
180 }
181
182 public Object getAt(final int index) {
183 final Iterator iter = iterator();
184 int count = 0;
185
186
187 while (iter.hasNext()) {
188 if (count++ == index) {
189 return iter.next();
190 } else {
191 iter.next();
192 }
193 }
194
195 throw new ArrayIndexOutOfBoundsException(index);
196 }
197
198 public Iterator depthFirst() {
199 return new Iterator() {
200 private final Stack stack = new Stack();
201 private Iterator iter = iterator();
202 private GPathResult next = getNextByDepth();
203
204 public boolean hasNext() {
205 return this.next != null;
206 }
207
208 public Object next() {
209 try {
210 return this.next;
211 } finally {
212 this.next = getNextByDepth();
213 }
214 }
215
216 public void remove() {
217 throw new UnsupportedOperationException();
218 }
219
220 private GPathResult getNextByDepth() {
221 while (this.iter.hasNext()) {
222 final GPathResult node = (GPathResult)this.iter.next();
223
224 this.stack.push(node);
225 this.stack.push(this.iter);
226 this.iter = node.children().iterator();
227 }
228
229 if (this.stack.empty()) {
230 return null;
231 } else {
232 this.iter = (Iterator)this.stack.pop();
233 return (GPathResult)this.stack.pop();
234 }
235 }
236 };
237 }
238
239 public List list() {
240 final Iterator iter = nodeIterator();
241 final List result = new LinkedList();
242
243 while (iter.hasNext()) {
244 result.add(new NodeChild((Node)iter.next(), this.parent, this.namespacePrefix, this.namespaceTagHints));
245 }
246
247 return result;
248 }
249
250 public abstract int size();
251
252 public abstract String text();
253
254 public abstract GPathResult parents();
255
256 public abstract Iterator childNodes();
257
258 public abstract Iterator iterator();
259
260 public abstract GPathResult find(Closure closure);
261
262 public abstract GPathResult findAll(Closure closure);
263
264 public abstract Iterator nodeIterator();
265 }