001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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 Feature Implementation 045 * 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 order to keep the 048 * implementation entry cost as low as possible, this specification mandates that a WFS implementation <b>must</b> 049 * 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 separator '/'.</li> 053 * <li>The first step of a relative location path <b>may</b> correspond to the root element of the feature property 054 * being referenced <b>or</b> to the root element of the feature type with the next step corresponding to the root 055 * element of the feature property being referenced</li> 056 * <li>Each subsequent step in the path <b>must</b> be composed of the abbreviated form of the <i>child::</i> axis 057 * specifier and the name of the feature property encoded as the principal node type of <i>element</i>. The abbreviated 058 * form of the <i>child::</i> axis specifier is to simply omit the specifier from the location step.</li> 059 * <li>Each step in the path may optionally contain a predicate composed of the predicate delimiters '[' and ']' and a 060 * number indicating which child of the context node is to be selected. This allows feature properties that may be 061 * repeated to be specifically referenced.</li> 062 * <li>The final step in a path may optionally be composed of the abbreviated form of the <i>attribute::</i> axis 063 * specifier, '@', and the name of a feature property encoded as the principal node type of <i>attribute::</i>.</li> 064 * </ol> 065 * <p> 066 * 067 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> 068 * @author last edited by: $Author: aionita $ 069 * 070 * @version $Revision: 23794 $, $Date: 2010-04-23 15:05:33 +0200 (Fr, 23 Apr 2010) $ 071 * 072 * @see PropertyPathStep 073 */ 074 public class PropertyPath implements Comparable<PropertyPath> { 075 076 private List<PropertyPathStep> steps; 077 078 /** 079 * Creates a new instance of <code>PropertyPath</code> with the specified steps. 080 * 081 * @param steps 082 * property path steps, may not be null 083 */ 084 public PropertyPath( List<PropertyPathStep> steps ) { 085 if ( steps.size() < 1 ) { 086 throw new IllegalArgumentException( "PropertyPath must contain at least one step." ); 087 } 088 this.steps = steps; 089 } 090 091 /** 092 * Returns the namespace bindings for the prefices that are used by this property path. 093 * 094 * @return the namespace bindings 095 */ 096 public NamespaceContext getNamespaceContext() { 097 NamespaceContext nsContext = new NamespaceContext(); 098 for ( PropertyPathStep step : steps ) { 099 QualifiedName elementName = step.getPropertyName(); 100 if ( elementName.getPrefix() != null && elementName.getNamespace() != null ) { 101 nsContext.addNamespace( elementName.getPrefix(), elementName.getNamespace() ); 102 } 103 } 104 return nsContext; 105 } 106 107 /** 108 * Returns the number of steps. 109 * 110 * @return the number of steps. 111 */ 112 public int getSteps() { 113 return this.steps.size(); 114 } 115 116 /** 117 * Setter method for steps 118 * 119 * @param steps 120 * a list of {@link PropertyPathStep}s 121 */ 122 public void setSteps( List<PropertyPathStep> steps ) { 123 this.steps = steps; 124 } 125 126 /** 127 * Returns the canonical string representation. 128 * 129 * @return canonical string representation 130 */ 131 public String getAsString() { 132 StringBuffer sb = new StringBuffer( 500 ); 133 for ( int i = 0; i < steps.size(); i++ ) { 134 sb.append( steps.get( i ).toString() ); 135 if ( i < steps.size() - 1 ) { 136 sb.append( '/' ); 137 } 138 } 139 return sb.toString(); 140 } 141 142 /** 143 * Returns the <code>PropertyPathStep</code> at the given index. 144 * 145 * @param i 146 * @return the <code>PropertyPathStep</code> at the given index 147 */ 148 public PropertyPathStep getStep( int i ) { 149 return this.steps.get( i ); 150 } 151 152 /** 153 * Returns all steps of the <code>PropertyPath</code>. 154 * 155 * @return all steps of the <code>PropertyPath</code> 156 */ 157 public List<PropertyPathStep> getAllSteps() { 158 return this.steps; 159 } 160 161 /** 162 * Adds the given <code>PropertyPathStep</code> to the end of the path. 163 * 164 * @param last 165 * <code>PropertyPathStep</code> to add 166 */ 167 public void append( PropertyPathStep last ) { 168 this.steps.add( last ); 169 } 170 171 /** 172 * Adds the given <code>PropertyPathStep</code> to the beginning of the path. 173 * 174 * @param first 175 * <code>PropertyPathStep</code> to add 176 */ 177 public void prepend( PropertyPathStep first ) { 178 this.steps.add( 0, first ); 179 } 180 181 @Override 182 public int hashCode() { 183 int hashCode = 0; 184 for ( PropertyPathStep step : steps ) { 185 hashCode += step.hashCode(); 186 } 187 return hashCode; 188 } 189 190 @Override 191 public boolean equals( Object obj ) { 192 if ( !( obj instanceof PropertyPath ) ) { 193 return false; 194 } 195 PropertyPath that = (PropertyPath) obj; 196 if ( this.getSteps() != that.getSteps() ) { 197 return false; 198 } 199 for ( int i = 0; i < this.getSteps(); i++ ) { 200 if ( !this.getStep( i ).equals( that.getStep( i ) ) ) { 201 return false; 202 } 203 } 204 return true; 205 } 206 207 @Override 208 public String toString() { 209 StringBuffer sb = new StringBuffer(); 210 for ( int i = 0; i < getSteps(); i++ ) { 211 sb.append( getStep( i ) ); 212 if ( i != getSteps() - 1 ) { 213 sb.append( "/" ); 214 } 215 } 216 return sb.toString(); 217 } 218 219 /** 220 * Compares this object with the specified object for order. 221 * <p> 222 * TODO use really unique string representations (namespaces!) + cache them 223 * 224 * @param that 225 * the PropertyPath to be compared 226 * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than 227 * the specified object 228 */ 229 public int compareTo( PropertyPath that ) { 230 return this.toString().compareTo( that.toString() ); 231 } 232 }