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 }