001    /*
002     * Copyright 2005 John G. Wilson
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     *
016     */
017    
018    package groovy.util.slurpersupport;
019    
020    import groovy.lang.Buildable;
021    import groovy.lang.Closure;
022    import groovy.lang.DelegatingMetaClass;
023    import groovy.lang.GroovyObjectSupport;
024    import groovy.lang.MetaClass;
025    import groovy.lang.Writable;
026    
027    import java.util.HashMap;
028    import java.util.Iterator;
029    import java.util.LinkedList;
030    import java.util.List;
031    import java.util.Map;
032    
033    
034    /**
035     * @author John Wilson
036     *
037     */
038    
039    public abstract class GPathResult extends GroovyObjectSupport implements Writable, Buildable {
040      protected final GPathResult parent;
041      protected final String name;
042      protected final String namespacePrefix;
043      protected final Map namespaceMap = new HashMap();
044      protected final Map namespaceTagHints;
045     
046      /**
047       * @param parent
048       * @param name
049       */
050      public GPathResult(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
051        if (parent == null) {
052          // we are the top of the tree
053          this.parent = this;
054          this.namespaceMap.put("xml", "http://www.w3.org/XML/1998/namespace");  // The XML namespace is always defined
055        } else {
056          this.parent = parent;
057          this.namespaceMap.putAll(parent.namespaceMap);
058        }
059        this.name = name;
060        this.namespacePrefix = namespacePrefix;
061        this.namespaceTagHints = namespaceTagHints;
062        
063        setMetaClass(getMetaClass()); // wrap the standard MetaClass with the delegate
064      }
065    
066        /* (non-Javadoc)
067         * @see groovy.lang.GroovyObjectSupport#setMetaClass(groovy.lang.MetaClass)
068         */
069        public void setMetaClass(final MetaClass metaClass) {
070        final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
071                                            /* (non-Javadoc)
072                                             * @see groovy.lang.DelegatingMetaClass#getAttribute(java.lang.Object, java.lang.String)
073                                             */
074                                            public Object getAttribute(Object object, String attribute) {
075                                                return GPathResult.this.getProperty("@" + attribute);
076                                            }
077                                        };
078    
079            super.setMetaClass(newMetaClass);
080        }
081    
082    public Object getProperty(final String property) {
083        if ("..".equals(property)) {
084          return parent();
085        } else if ("*".equals(property)){
086          return children();
087        } else if (property.startsWith("@")) {
088          if (property.indexOf(":") != -1) {
089          final int i = property.indexOf(":");
090    
091            return new Attributes(this, "@" + property.substring(i + 1), property.substring(1, i), this.namespaceTagHints);
092          } else {
093            return new Attributes(this, property, this.namespaceTagHints);
094          }
095        } else {
096          if (property.indexOf(":") != -1) {
097          final int i = property.indexOf(":");
098    
099            return new NodeChildren(this, property.substring(i + 1), property.substring(0, i), this.namespaceTagHints);
100          } else {
101            return new NodeChildren(this, property, this.namespaceTagHints);
102          }
103        }
104      }
105    
106      public String name() {
107        return this.name;
108      }
109    
110      public GPathResult parent() {
111        return this.parent;
112      }
113    
114      public GPathResult children() {
115        return new NodeChildren(this, this.namespaceTagHints);
116      }
117    
118      public String toString() {
119        return text();
120      }
121      
122      public GPathResult declareNamespace(final Map newNamespaceMapping) {
123        this.namespaceMap.putAll(newNamespaceMapping);
124        
125        return this; 
126      }
127      
128      /* (non-Javadoc)
129       * @see java.lang.Object#equals(java.lang.Object)
130       */
131      public boolean equals(Object obj) {
132        return text().equals(obj.toString());
133      }
134    
135      public Object getAt(final int index) {
136      final Iterator iter = iterator();
137      int count = 0;
138      
139      
140        while (iter.hasNext()) {
141          if (count++ == index) {
142            return iter.next();
143          } else {
144            iter.next();
145          }
146        }
147        
148        throw new ArrayIndexOutOfBoundsException(index);
149      }
150      
151      public List list() {
152      final Iterator iter = nodeIterator();
153      final List result = new LinkedList();
154      
155        while (iter.hasNext()) {
156          result.add(iter.next());
157        }
158        
159        return result;
160      }
161    
162      public abstract int size();
163      
164      public abstract String text();
165      
166      public abstract GPathResult parents();
167      
168      public abstract Iterator childNodes();
169      
170      public abstract Iterator iterator();
171      
172      public abstract GPathResult find(Closure closure);
173      
174      public abstract GPathResult findAll(Closure closure);
175      
176      public abstract Iterator nodeIterator();
177    }