001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/ogcbase/PropertyPath.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.ogcbase;
044:
045: import java.util.List;
046:
047: import org.deegree.datatypes.QualifiedName;
048: import org.deegree.framework.xml.NamespaceContext;
049:
050: /**
051: * Represents a subset of the XPath expression language as described in section 7.4.2 of the Web
052: * Feature Implementation Specification 1.1.0 (but is used by other OGC specifications as well).
053: * <p>
054: * This specification does not require a WFS implementation to support the full XPath language. In
055: * order to keep the implementation entry cost as low as possible, this specification mandates that
056: * a WFS implementation <b>must</b> support the following subset of the XPath language:
057: * <ol>
058: * <li>A WFS implementation <b>must</b> support <i>abbreviated relative location</i> paths.</li>
059: * <li>Relative location paths are composed of one or more <i>steps</i> separated by the path
060: * separator '/'.</li>
061: * <li>The first step of a relative location path <b>may</b> correspond to the root element of the
062: * feature property being referenced <b>or</b> to the root element of the feature type with the
063: * next step corresponding to the root element of the feature property being referenced</li>
064: * <li>Each subsequent step in the path <b>must</b> be composed of the abbreviated form of the
065: * <i>child::</i> axis specifier and the name of the feature property encoded as the principal node
066: * type of <i>element</i>. The abbreviated form of the <i>child::</i> axis specifier is to simply
067: * omit the specifier from the location step.</li>
068: * <li>Each step in the path may optionally contain a predicate composed of the predicate
069: * delimiters '[' and ']' and a number indicating which child of the context node is to be selected.
070: * This allows feature properties that may be repeated to be specifically referenced.</li>
071: * <li>The final step in a path may optionally be composed of the abbreviated form of the
072: * <i>attribute::</i> axis specifier, '@', and the name of a feature property encoded as the
073: * principal node type of <i>attribute::</i>.</li>
074: * </ol>
075: * <p>
076: *
077: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
078: * @author last edited by: $Author: apoth $
079: *
080: * @version $Revision: 9344 $, $Date: 2007-12-27 08:21:56 -0800 (Thu, 27 Dec 2007) $
081: *
082: * @see PropertyPathStep
083: */
084: public class PropertyPath implements Comparable<PropertyPath> {
085:
086: private List<PropertyPathStep> steps;
087:
088: /**
089: * Creates a new instance of <code>PropertyPath</code> with the specified steps.
090: *
091: * @param steps
092: * property path steps, may not be null
093: */
094: public PropertyPath(List<PropertyPathStep> steps) {
095: if (steps.size() < 1) {
096: throw new IllegalArgumentException(
097: "PropertyPath must contain at least one step.");
098: }
099: this .steps = steps;
100: }
101:
102: /**
103: * Returns the namespace bindings for the prefices that are used by this property path.
104: *
105: * @return the namespace bindings
106: */
107: public NamespaceContext getNamespaceContext() {
108: NamespaceContext nsContext = new NamespaceContext();
109: for (PropertyPathStep step : steps) {
110: QualifiedName elementName = step.getPropertyName();
111: if (elementName.getPrefix() != null
112: && elementName.getNamespace() != null) {
113: nsContext.addNamespace(elementName.getPrefix(),
114: elementName.getNamespace());
115: }
116: }
117: return nsContext;
118: }
119:
120: /**
121: * Returns the number of steps.
122: *
123: * @return the number of steps.
124: */
125: public int getSteps() {
126: return this .steps.size();
127: }
128:
129: /**
130: * Returns the canonical string representation.
131: *
132: * @return canonical string representation
133: */
134: public String getAsString() {
135: StringBuffer sb = new StringBuffer(500);
136: for (int i = 0; i < steps.size(); i++) {
137: sb.append(steps.get(i).toString());
138: if (i < steps.size() - 1) {
139: sb.append('/');
140: }
141: }
142: return sb.toString();
143: }
144:
145: /**
146: * Returns the <code>PropertyPathStep</code> at the given index.
147: *
148: * @param i
149: * @return the <code>PropertyPathStep</code> at the given index
150: */
151: public PropertyPathStep getStep(int i) {
152: return this .steps.get(i);
153: }
154:
155: /**
156: * Returns all steps of the <code>PropertyPath</code>.
157: *
158: * @return all steps of the <code>PropertyPath</code>
159: */
160: public List<PropertyPathStep> getAllSteps() {
161: return this .steps;
162: }
163:
164: /**
165: * Adds the given <code>PropertyPathStep</code> to the end of the path.
166: *
167: * @param last
168: * <code>PropertyPathStep</code> to add
169: */
170: public void append(PropertyPathStep last) {
171: this .steps.add(last);
172: }
173:
174: /**
175: * Adds the given <code>PropertyPathStep</code> to the beginning of the path.
176: *
177: * @param first
178: * <code>PropertyPathStep</code> to add
179: */
180: public void prepend(PropertyPathStep first) {
181: this .steps.add(0, first);
182: }
183:
184: @Override
185: public int hashCode() {
186: int hashCode = 0;
187: for (PropertyPathStep step : steps) {
188: hashCode += step.hashCode();
189: }
190: return hashCode;
191: }
192:
193: @Override
194: public boolean equals(Object obj) {
195: if (!(obj instanceof PropertyPath)) {
196: return false;
197: }
198: PropertyPath that = (PropertyPath) obj;
199: if (this .getSteps() != that.getSteps()) {
200: return false;
201: }
202: for (int i = 0; i < this .getSteps(); i++) {
203: if (!this .getStep(i).equals(that.getStep(i))) {
204: return false;
205: }
206: }
207: return true;
208: }
209:
210: @Override
211: public String toString() {
212: StringBuffer sb = new StringBuffer();
213: for (int i = 0; i < getSteps(); i++) {
214: sb.append(getStep(i));
215: if (i != getSteps() - 1) {
216: sb.append("/");
217: }
218: }
219: return sb.toString();
220: }
221:
222: /**
223: * Compares this object with the specified object for order.
224: * <p>
225: * TODO use really unique string representations (namespaces!) + cache them
226: *
227: * @param that
228: * the PropertyPath to be compared
229: * @return a negative integer, zero, or a positive integer as this object is less than, equal
230: * to, or greater than the specified object
231: */
232: public int compareTo(PropertyPath that) {
233: return this.toString().compareTo(that.toString());
234: }
235: }
|