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 }