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