View Javadoc

1   /*
2    * Copyright 2005 John G. Wilson
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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        // we are the top of the tree
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()); // wrap the standard MetaClass with the delegate
73    }
74  
75      /* (non-Javadoc)
76       * @see groovy.lang.GroovyObjectSupport#setMetaClass(groovy.lang.MetaClass)
77       */
78      public void setMetaClass(final MetaClass metaClass) {
79      final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
80                                          /* (non-Javadoc)
81                                           * @see groovy.lang.DelegatingMetaClass#getAttribute(java.lang.Object, java.lang.String)
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   /* (non-Javadoc)
176    * @see java.lang.Object#equals(java.lang.Object)
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 }