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 }