All Downloads are FREE. Search and download functionalities are using the official Maven repository.

groovy.util.slurpersupport.GPathResult Maven / Gradle / Ivy

There is a newer version: 3.0.22
Show newest version
/*
 * Copyright 2003-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package groovy.util.slurpersupport;

import groovy.lang.Buildable;
import groovy.lang.Closure;
import groovy.lang.DelegatingMetaClass;
import groovy.lang.GString;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.IntRange;
import groovy.lang.MetaClass;
import groovy.lang.Writable;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.codehaus.groovy.runtime.DefaultGroovyMethods;


/**
 * @author John Wilson
 */

public abstract class GPathResult extends GroovyObjectSupport implements Writable, Buildable {
    protected final GPathResult parent;
    protected final String name;
    protected final String namespacePrefix;
    protected final Map namespaceMap = new HashMap();
    protected final Map namespaceTagHints;

    /**
     * @param parent
     * @param name
     * @param namespacePrefix
     * @param namespaceTagHints
     */
    public GPathResult(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
        if (parent == null) {
            // we are the top of the tree
            this.parent = this;
            this.namespaceMap.put("xml", "http://www.w3.org/XML/1998/namespace");  // The XML namespace is always defined
        } else {
            this.parent = parent;
            this.namespaceMap.putAll(parent.namespaceMap);
        }
        this.name = name;
        this.namespacePrefix = namespacePrefix;
        this.namespaceTagHints = namespaceTagHints;

        setMetaClass(getMetaClass()); // wrap the standard MetaClass with the delegate
    }

    /* (non-Javadoc)
     * @see groovy.lang.GroovyObjectSupport#setMetaClass(groovy.lang.MetaClass)
     */
    public void setMetaClass(final MetaClass metaClass) {
        final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
            /* (non-Javadoc)
            * @see groovy.lang.DelegatingMetaClass#getAttribute(java.lang.Object, java.lang.String)
            */
            public Object getAttribute(final Object object, final String attribute) {
                return GPathResult.this.getProperty("@" + attribute);
            }
            
            public void setAttribute(final Object object, final String attribute, final Object newValue) {
                GPathResult.this.setProperty("@" + attribute, newValue);
            }
        };
        super.setMetaClass(newMetaClass);
    }

    public Object getProperty(final String property) {
        if ("..".equals(property)) {
            return parent();
        } else if ("*".equals(property)) {
            return children();
        } else if ("**".equals(property)) {
            return depthFirst();
        } else if (property.startsWith("@")) {
            if (property.indexOf(":") != -1) {
                final int i = property.indexOf(":");
                return new Attributes(this, "@" + property.substring(i + 1), property.substring(1, i), this.namespaceTagHints);
            } else {
                return new Attributes(this, property, this.namespaceTagHints);
            }
        } else {
            if (property.indexOf(":") != -1) {
                final int i = property.indexOf(":");
                return new NodeChildren(this, property.substring(i + 1), property.substring(0, i), this.namespaceTagHints);
            } else {
                return new NodeChildren(this, property, this.namespaceTagHints);
            }
        }
    }

    public void setProperty(final String property, final Object newValue) {
        if (property.startsWith("@")) {
            if (newValue instanceof String || newValue instanceof GString) {
            final Iterator iter = iterator();
            
                while (iter.hasNext()) {
                final NodeChild child = (NodeChild)iter.next();
                
                    child.attributes().put(property.substring(1), newValue);
                }
            }
        } else {
        final GPathResult result = new NodeChildren(this, property, this.namespaceTagHints);
        
            if (newValue instanceof Map) {
            final Iterator iter = ((Map)newValue).entrySet().iterator();
            
                while (iter.hasNext()) {
                final Map.Entry entry = (Map.Entry)iter.next();
                
                    result.setProperty("@" + entry.getKey(), entry.getValue());
                }
            } else {           
              if (newValue instanceof Closure) {
                  result.replaceNode((Closure)newValue);
              } else {
                  result.replaceBody(newValue);
              }
            }
        }
    }
    
    public Object leftShift(final Object newValue) {
        appendNode(newValue);
        return this;
    }
    
    public Object plus(final Object newValue) {
        this.replaceNode(new Closure(this) {
            public void doCall(Object[] args) {
            final GroovyObject delegate = (GroovyObject)getDelegate();
             
                delegate.getProperty("mkp");
                delegate.invokeMethod("yield", args);
                
                delegate.getProperty("mkp");
                delegate.invokeMethod("yield", new Object[]{newValue});
            }
        });
        
        return this;
    }
    
    protected abstract void replaceNode(Closure newValue);
    
    protected abstract void replaceBody(Object newValue);
    
    protected abstract void appendNode(Object newValue);

    public String name() {
        return this.name;
    }

    public GPathResult parent() {
        return this.parent;
    }

    public GPathResult children() {
        return new NodeChildren(this, this.namespaceTagHints);
    }
    
    public String lookupNamespace(final String prefix) {
        return (String)this.namespaceTagHints.get(prefix);
    }

    public String toString() {
        return text();
    }

    public Integer toInteger() {
        return DefaultGroovyMethods.toInteger(text());
    }

    public Long toLong() {
        return DefaultGroovyMethods.toLong(text());
    }

    public Float toFloat() {
        return DefaultGroovyMethods.toFloat(text());
    }

    public Double toDouble() {
        return DefaultGroovyMethods.toDouble(text());
    }

    public BigDecimal toBigDecimal() {
        return DefaultGroovyMethods.toBigDecimal(text());
    }

    public BigInteger toBigInteger() {
        return DefaultGroovyMethods.toBigInteger(text());
    }

    public URL toURL() throws MalformedURLException {
        return DefaultGroovyMethods.toURL(text());
    }

    public URI toURI() throws URISyntaxException {
        return DefaultGroovyMethods.toURI(text());
    }

    public Boolean toBoolean() {
        return DefaultGroovyMethods.toBoolean(text());
    }

    public GPathResult declareNamespace(final Map newNamespaceMapping) {
        this.namespaceMap.putAll(newNamespaceMapping);
        return this;
    }

    /* (non-Javadoc)
    * @see java.lang.Object#equals(java.lang.Object)
    */
    public boolean equals(Object obj) {
        return text().equals(obj.toString());
    }

    public Object getAt(final int index) {
        if (index < 0) throw new ArrayIndexOutOfBoundsException(index);
        
        final Iterator iter = iterator();
        int count = 0;
    
        while (iter.hasNext()) {
            if (count++ == index) {
                return iter.next();
            } else {
                iter.next();
            }
        }
        
        return new NoChildren(this, this.name, this.namespaceTagHints);
    }

    public Object getAt(final IntRange range) {
    final int from = range.getFromInt();
    final int to = range.getToInt();
    
        if (range.isReverse()) {
            throw new GroovyRuntimeException("Reverse ranges not supported, range supplied is ["+ to + ".." + from + "]");
        } else if (from < 0 || to < 0) {
            throw new GroovyRuntimeException("Negative range indexes not supported, range supplied is ["+ from + ".." + to + "]");
        } else {
            return new Iterator() {
            final Iterator iter = iterator();
            Object next;
            int count = 0;
            
               public boolean hasNext() {
                   if (count <= to) {
                       while (iter.hasNext()) {
                           if (count++ >= from) {
                               this.next = iter.next();
                               return true;
                           } else {
                               iter.next();
                           }
                       }
                   }

                   return false;
                }

                public Object next() {
                    return next;
                }

                public void remove() {
                    throw new UnsupportedOperationException();
                }
                
            };
        }
     }

    public void putAt(final int index, final Object newValue) {
    final GPathResult result = (GPathResult)getAt(index);
    
        if (newValue instanceof Closure) {
            result.replaceNode((Closure)newValue);
        } else {
            result.replaceBody(newValue);
        }
    }
    
    public Iterator depthFirst() {
        return new Iterator() {
            private final List list = new LinkedList();
            private final Stack stack = new Stack();
            private Iterator iter = iterator();
            private GPathResult next = getNextByDepth();

            public boolean hasNext() {
                return this.next != null;
            }

            public Object next() {
                try {
                    return this.next;
                } finally {
                    this.next = getNextByDepth();
                }
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

            private GPathResult getNextByDepth() {
                while (this.iter.hasNext()) {
                    final GPathResult node = (GPathResult) this.iter.next();
                    this.list.add(node);
                    this.stack.push(this.iter);
                    this.iter = node.children().iterator();
                }

                if (this.list.isEmpty()) {
                    return null;
                } else {
                    GPathResult result = (GPathResult) this.list.get(0);
                    this.list.remove(0);
                    this.iter = (Iterator) this.stack.pop();
                    return result;
                }
            }
        };
    }

    /**
     * An iterator useful for traversing XML documents/fragments in breadth-first order.
     *
     * @return Iterator the iterator of GPathResult objects
     */
    public Iterator breadthFirst() {
        return new Iterator() {
            private final List list = new LinkedList();
            private Iterator iter = iterator();
            private GPathResult next = getNextByBreadth();

            public boolean hasNext() {
                return this.next != null;
            }

            public Object next() {
                try {
                    return this.next;
                } finally {
                    this.next = getNextByBreadth();
                }
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

            private GPathResult getNextByBreadth() {
                List children = new ArrayList();
                while (this.iter.hasNext() || !children.isEmpty()) {
                    if (this.iter.hasNext()) {
                        final GPathResult node = (GPathResult) this.iter.next();
                        this.list.add(node);
                        this.list.add(this.iter);
                        children.add(node.children());
                    } else {
                        List nextLevel = new ArrayList();
                        for (int i = 0; i < children.size(); i++) {
                            GPathResult next = (GPathResult) children.get(i);
                            Iterator iterator = next.iterator();
                            while (iterator.hasNext()) {
                                nextLevel.add(iterator.next());
                            }
                        }
                        this.iter = nextLevel.iterator();
                        children = new ArrayList();
                    }
                }
                if (this.list.isEmpty()) {
                    return null;
                } else {
                    GPathResult result = (GPathResult) this.list.get(0);
                    this.list.remove(0);
                    this.iter = (Iterator) this.list.get(0);
                    this.list.remove(0);
                    return result;
                }
            }
        };
    }

    public List list() {
        final Iterator iter = nodeIterator();
        final List result = new LinkedList();
        while (iter.hasNext()) {
            result.add(new NodeChild((Node) iter.next(), this.parent, this.namespacePrefix, this.namespaceTagHints));
        }
        return result;
    }

    public boolean isEmpty() {
        return size() == 0;
    }
    
    public Closure getBody() {
        return new Closure(this.parent(),this) {
            public void doCall(Object[] args) {
                final GroovyObject delegate = (GroovyObject)getDelegate();
                final GPathResult thisObject = (GPathResult)getThisObject();

                Node node = (Node)thisObject.getAt(0);
                List children = node.children();

                for(int i=0;  i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy