//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/model/feature/GMLFeatureDocument.java,v 1.32 2006/11/27 09:07:52 poth Exp $ /*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001-2006 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/deegree/ lat/lon GmbH http://www.lat-lon.de This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstraße 19 53177 Bonn Germany E-Mail: poth@lat-lon.de Prof. Dr. Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: greve@giub.uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.model.feature; import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.deegree.datatypes.QualifiedName; import org.deegree.datatypes.Types; import org.deegree.datatypes.UnknownTypeException; import org.deegree.framework.log.ILogger; import org.deegree.framework.log.LoggerFactory; import org.deegree.framework.util.TimeTools; import org.deegree.framework.xml.ElementList; import org.deegree.framework.xml.XMLParsingException; import org.deegree.framework.xml.XMLTools; import org.deegree.model.crs.UnknownCRSException; import org.deegree.model.feature.schema.FeaturePropertyType; import org.deegree.model.feature.schema.FeatureType; import org.deegree.model.feature.schema.GMLSchema; import org.deegree.model.feature.schema.GMLSchemaDocument; import org.deegree.model.feature.schema.GeometryPropertyType; import org.deegree.model.feature.schema.MultiGeometryPropertyType; import org.deegree.model.feature.schema.PropertyType; import org.deegree.model.feature.schema.SimplePropertyType; import org.deegree.model.spatialschema.GMLGeometryAdapter; import org.deegree.model.spatialschema.Geometry; import org.deegree.model.spatialschema.GeometryException; import org.deegree.ogcbase.CommonNamespaces; import org.deegree.ogcbase.GMLDocument; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Text; import org.xml.sax.SAXException; /** * Parser and wrapper class for GML feature documents. * <p> * Has validation capabilities: if the schema is provided or the document contains a reference * to a schema the structure of the generated features is checked. If no schema information is * available, feature + property types are heuristically determined from the feature instance in * the document (guessing of simple property types can be turned off, because it may cause * unwanted effects). * </p> * <p> * Has some basic understanding of XLink: Supports internal XLinks (i.e. the content for a feature * is given by a reference to a feature element in the same document). No support for external * XLinks yet. * </p> * * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> * @author last edited by: $Author: poth $ * * @version $Revision: 1.32 $, $Date: 2006/11/27 09:07:52 $ */ public class GMLFeatureDocument extends GMLDocument { private static final long serialVersionUID = -7626943858143104276L; private final static ILogger LOG = LoggerFactory.getLogger( GMLFeatureDocument.class ); private static String FID = "fid"; private static String GMLID = "id"; private static URI GMLNS = CommonNamespaces.GMLNS; private static String GMLID_NS = CommonNamespaces.GMLNS.toString(); private static QualifiedName PROP_NAME_BOUNDED_BY = new QualifiedName( "boundedBy", GMLNS ); private static QualifiedName PROP_NAME_DESCRIPTION = new QualifiedName( "description", GMLNS ); private static QualifiedName PROP_NAME_NAME = new QualifiedName( "name", GMLNS ); private static QualifiedName PROP_NAME_WKB_GEOM = new QualifiedName( "wkbGeom", GMLNS ); private static QualifiedName TYPE_NAME_BOX = new QualifiedName( "Box", GMLNS ); private static QualifiedName TYPE_NAME_LINESTRING = new QualifiedName( "LineString", GMLNS ); private static QualifiedName TYPE_NAME_MULTIGEOMETRY = new QualifiedName( "MultiGeometry", GMLNS ); private static QualifiedName TYPE_NAME_MULTILINESTRING = new QualifiedName( "MultiLineString", GMLNS ); private static QualifiedName TYPE_NAME_MULTIPOINT = new QualifiedName( "MultiPoint", GMLNS ); private static QualifiedName TYPE_NAME_MULTIPOLYGON = new QualifiedName( "MultiPolygon", GMLNS ); private static QualifiedName TYPE_NAME_POINT = new QualifiedName( "Point", GMLNS ); private static QualifiedName TYPE_NAME_POLYGON = new QualifiedName( "Polygon", GMLNS ); private static QualifiedName TYPE_NAME_SURFACE = new QualifiedName( "Surface", GMLNS ); private static QualifiedName TYPE_NAME_CURVE = new QualifiedName( "Curve", GMLNS ); private static QualifiedName TYPE_NAME_MULTISURFACE = new QualifiedName( "MultiSurface", GMLNS ); private static QualifiedName TYPE_NAME_MULTICURVE = new QualifiedName( "MultiCurve", GMLNS ); // key: namespace URI, value: GMLSchema protected Map<URI, GMLSchema> gmlSchemaMap; // key: feature id, value: Feature protected Map<String, Feature> featureMap = new HashMap<String, Feature>(); // value: XLinkedFeatureProperty protected Collection<XLinkedFeatureProperty> xlinkPropertyList = new ArrayList<XLinkedFeatureProperty>(); private boolean guessSimpleTypes = false; /** * Creates a new instance of <code>GMLFeatureDocument</code>. * <p> * Simple types encountered during parsing are "guessed", i.e. the parser tries to convert * the values to double, integer, calendar, etc. However, this may lead to unwanted results, * e.g. a property value of "054604" is converted to "54604". */ public GMLFeatureDocument() { super(); } /** * Creates a new instance of <code>GMLFeatureDocument</code>. * <p> * @param guessSimpleTypes * set to true, if simple types should be "guessed" during parsing */ public GMLFeatureDocument( boolean guessSimpleTypes ) { super(); this.guessSimpleTypes = guessSimpleTypes; } /** * Explicitly sets the GML schema information that the document must comply to. * <p> * This overrides any schema information that the document refers to. * * @param gmlSchemaMap * key: namespace URI, value: GMLSchema */ public void setSchemas( Map<URI, GMLSchema> gmlSchemaMap ) { this.gmlSchemaMap = gmlSchemaMap; } /** * Returns the object representation for the root feature element. * * @return object representation for the root feature element. * @throws XMLParsingException * @throws UnknownCRSException */ public Feature parseFeature() throws XMLParsingException, UnknownCRSException { Feature feature = this.parseFeature( this.getRootElement() ); resolveXLinkReferences(); return feature; } /** * Returns the object representation for the given feature element. * * @param element * feature element * @return object representation for the given feature element. * @throws XMLParsingException * @throws UnknownCRSException */ protected Feature parseFeature( Element element ) throws XMLParsingException, UnknownCRSException { Feature feature = null; String fid = parseFeatureId( element ); FeatureType featureType = getFeatureType( element ); ElementList childList = XMLTools.getChildElements( element ); Collection<FeatureProperty> propertyList = new ArrayList<FeatureProperty>( childList.getLength() ); for ( int i = 0; i < childList.getLength(); i++ ) { Element propertyElement = childList.item( i ); QualifiedName propertyName = getQualifiedName( propertyElement ); if ( PROP_NAME_BOUNDED_BY.equals( propertyName ) || PROP_NAME_WKB_GEOM.equals( propertyName ) ) { // TODO } else if ( PROP_NAME_NAME.equals( propertyName ) || PROP_NAME_DESCRIPTION.equals( propertyName ) ) { String s = XMLTools.getStringValue( propertyElement ); if ( s != null ) { s = s.trim(); } FeatureProperty property = createSimpleProperty( s, propertyName, Types.VARCHAR ); if ( property != null ) { propertyList.add( property ); } } else { FeatureProperty property = parseProperty( childList.item( i ), featureType ); if ( property != null ) { propertyList.add( property ); } } } FeatureProperty[] featureProperties = propertyList.toArray( new FeatureProperty[propertyList.size()] ); feature = FeatureFactory.createFeature( fid, featureType, featureProperties ); if ( !"".equals( fid ) ) { if ( this.featureMap.containsKey( fid ) ) { String msg = Messages.format( "ERROR_FEATURE_ID_NOT_UNIQUE", fid ); throw new XMLParsingException( msg ); } this.featureMap.put( fid, feature ); } return feature; } /** * Returns the object representation for the given property element. * * @param propertyElement * property element * @param featureType * feature type of the feature that the property belongs to * @return object representation for the given property element. * @throws XMLParsingException * @throws UnknownCRSException */ public FeatureProperty parseProperty( Element propertyElement, FeatureType featureType ) throws XMLParsingException, UnknownCRSException { FeatureProperty property = null; QualifiedName propertyName = getQualifiedName( propertyElement ); PropertyType propertyType = featureType.getProperty( propertyName ); if ( propertyType == null ) { throw new XMLParsingException( Messages.format( "ERROR_NO_PROPERTY_TYPE", propertyName ) ); } if ( propertyType instanceof SimplePropertyType ) { int typeCode = propertyType.getType(); String s = XMLTools.getStringValue( propertyElement ); // TODO remove this hack if ( s == null || s.length() == 0 ) { return null; } if ( XMLTools.getNode( propertyElement, "text()", nsContext ) == null ) { return null; } s = s.trim(); property = createSimpleProperty( s, propertyName, typeCode ); } else if ( propertyType instanceof GeometryPropertyType ) { Element contentElement = XMLTools.getFirstChildElement( propertyElement ); if ( contentElement == null ) { String msg = Messages.format( "ERROR_PROPERTY_NO_CHILD", propertyName, "geometry" ); throw new XMLParsingException( msg ); } property = createGeometryProperty( contentElement, propertyName ); } else if ( propertyType instanceof MultiGeometryPropertyType ) { throw new XMLParsingException( "Handling of MultiGeometryPropertyType not " + "implemented in GMLFeatureDocument yet." ); } else if ( propertyType instanceof FeaturePropertyType ) { Element contentElement = XMLTools.getFirstChildElement( propertyElement ); if ( contentElement == null ) { // check if feature content is xlinked Text xlinkHref = (Text) XMLTools.getNode( propertyElement, "@xlink:href/text()", nsContext ); if ( xlinkHref == null ) { String msg = Messages.format( "ERROR_INVALID_FEATURE_PROPERTY", propertyName ); throw new XMLParsingException( msg ); } String href = xlinkHref.getData(); if ( !href.startsWith( "#" ) ) { String msg = Messages.format( "ERROR_EXTERNAL_XLINK_NOT_SUPPORTED", href ); throw new XMLParsingException( msg ); } String fid = href.substring( 1 ); property = new XLinkedFeatureProperty( propertyName, fid ); xlinkPropertyList.add( (XLinkedFeatureProperty) property ); } else { // feature content is given inline Feature propertyValue = parseFeature( contentElement ); property = FeatureFactory.createFeatureProperty( propertyName, propertyValue ); } } return property; } protected void resolveXLinkReferences() throws XMLParsingException { Iterator iter = this.xlinkPropertyList.iterator(); while ( iter.hasNext() ) { XLinkedFeatureProperty xlinkProperty = (XLinkedFeatureProperty) iter.next(); String fid = xlinkProperty.getTargetFeatureId(); Feature targetFeature = this.featureMap.get( fid ); if ( targetFeature == null ) { String msg = Messages.format( "ERROR_XLINK_NOT_RESOLVABLE", fid ); throw new XMLParsingException( msg ); } xlinkProperty.setValue( targetFeature ); } } /** * Creates a simple property from the given parameters. * <p> * Converts the string value to the given target type. * * @param s * string value from a simple property to be converted * @param propertyName * name of the simple property * @param typeCode * target type code * @return property value in the given target type. * @throws XMLParsingException */ private FeatureProperty createSimpleProperty( String s, QualifiedName propertyName, int typeCode ) throws XMLParsingException { Object propertyValue = null; switch ( typeCode ) { case Types.VARCHAR: { propertyValue = s; break; } case Types.INTEGER: case Types.SMALLINT: { try { propertyValue = new Integer( s ); } catch ( NumberFormatException e ) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Integer" ); throw new XMLParsingException( msg ); } break; } case Types.NUMERIC: case Types.DOUBLE: { try { propertyValue = new Double( s ); } catch ( NumberFormatException e ) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Double" ); throw new XMLParsingException( msg ); } break; } case Types.DECIMAL: case Types.FLOAT: { try { propertyValue = new Float( s ); } catch ( NumberFormatException e ) { String msg = Messages.format( "ERROR_CONVERTING_PROPERTY", s, propertyName, "Float" ); throw new XMLParsingException( msg ); } break; } case Types.BOOLEAN: { propertyValue = new Boolean( s ); break; } case Types.DATE: { propertyValue = TimeTools.createCalendar( s ).getTime(); break; } default: { String typeString = "" + typeCode; try { typeString = Types.getTypeNameForSQLTypeCode( typeCode ); } catch ( UnknownTypeException e ) { LOG.logError( "No type name for code: " + typeCode ); } String msg = Messages.format( "ERROR_UNHANDLED_TYPE", "" + typeString ); LOG.logError( msg ); throw new XMLParsingException( msg ); } } FeatureProperty property = FeatureFactory.createFeatureProperty( propertyName, propertyValue ); return property; } /** * Creates a geometry property from the given parameters. * * @param contentElement * child element of a geometry property to be converted * @param propertyName * name of the geometry property * @return geometry property * @throws XMLParsingException */ private FeatureProperty createGeometryProperty( Element contentElement, QualifiedName propertyName ) throws XMLParsingException { Geometry propertyValue = null; try { propertyValue = GMLGeometryAdapter.wrap( contentElement ); } catch ( GeometryException e ) { e.printStackTrace(); String msg = Messages.format( "ERROR_CONVERTING_GEOMETRY_PROPERTY", propertyName, e.getMessage() ); throw new XMLParsingException( msg ); } FeatureProperty property = FeatureFactory.createFeatureProperty( propertyName, propertyValue ); return property; } /** * Determines and retrieves the GML schemas that the document refers to. * * @return the GML schemas that are attached to the document, keys are URIs (namespaces), values * are GMLSchemas. * @throws XMLParsingException * @throws UnknownCRSException */ protected Map<URI, GMLSchema> getGMLSchemas() throws XMLParsingException, UnknownCRSException { if ( this.gmlSchemaMap == null ) { gmlSchemaMap = new HashMap<URI, GMLSchema>(); Map schemaMap = getAttachedSchemas(); Iterator it = schemaMap.keySet().iterator(); while ( it.hasNext() ) { URI nsURI = (URI) it.next(); URL schemaURL = (URL) schemaMap.get( nsURI ); GMLSchemaDocument schemaDocument = new GMLSchemaDocument(); LOG.logDebug( "Retrieving schema document for namespace '" + nsURI + "' from URL '" + schemaURL + "'." ); try { schemaDocument.load( schemaURL ); GMLSchema gmlSchema = schemaDocument.parseGMLSchema(); gmlSchemaMap.put( nsURI, gmlSchema ); } catch ( IOException e ) { String msg = Messages.format( "ERROR_RETRIEVING_SCHEMA", schemaURL, e.getMessage() ); throw new XMLParsingException( msg ); } catch ( SAXException e ) { String msg = Messages.format( "ERROR_SCHEMA_NOT_XML", schemaURL, e.getMessage() ); throw new XMLParsingException( msg ); } catch ( XMLParsingException e ) { String msg = Messages.format( "ERROR_SCHEMA_PARSING1", schemaURL, e.getMessage() ); throw new XMLParsingException( msg ); } } } return this.gmlSchemaMap; } /** * Returns the GML schema for the given namespace. * * @param ns * @return the GML schema for the given namespace if it is declared, null otherwise. * @throws XMLParsingException * @throws UnknownCRSException */ protected GMLSchema getSchemaForNamespace( URI ns ) throws XMLParsingException, UnknownCRSException { Map<URI, GMLSchema> gmlSchemaMap = getGMLSchemas(); GMLSchema schema = gmlSchemaMap.get( ns ); return schema; } /** * Returns the feature type with the given name. * <p> * If schema information is available and a feature type with the given name is not defined, * an XMLParsingException is thrown. * * @param ftName * feature type to look up * @return the feature type with the given name if it is declared, null otherwise. * @throws XMLParsingException * @throws UnknownCRSException */ protected FeatureType getFeatureType( QualifiedName ftName ) throws XMLParsingException, UnknownCRSException { FeatureType featureType = null; if ( this.gmlSchemaMap != null ) { GMLSchema schema = getSchemaForNamespace( ftName.getNamespace() ); if ( schema == null ) { String msg = Messages.format( "ERROR_SCHEMA_NO_SCHEMA_FOR_NS", ftName.getNamespace() ); throw new XMLParsingException( msg ); } featureType = schema.getFeatureType( ftName ); if ( featureType == null ) { String msg = Messages.format( "ERROR_SCHEMA_FEATURE_TYPE_UNKNOWN", ftName ); throw new XMLParsingException( msg ); } } return featureType; } /** * Parses the feature id attribute from the given feature element. * <p> * Looks after 'gml:id' (GML 3 style) first, if no such attribute is present, the 'fid' (GML 2 * style) attribute is used. * * @param featureElement * @return the feature id, this is "" if neither a 'gml:id' nor a 'fid' attribute is present */ protected String parseFeatureId( Element featureElement ) { String fid = featureElement.getAttributeNS( GMLID_NS, GMLID ); if ( fid.length() == 0 ) { fid = featureElement.getAttribute( FID ); } return fid; } /** * Returns the feature type for the given feature element. * <p> * If a schema defines a feature type with the element's name, it is returned. Otherwise, a * feature type is generated that matches the child elements (properties) of the feature. * * @param element * feature element * @return the feature type. * @throws XMLParsingException * @throws UnknownCRSException */ private FeatureType getFeatureType( Element element ) throws XMLParsingException, UnknownCRSException { QualifiedName ftName = getQualifiedName( element ); FeatureType featureType = getFeatureType( ftName ); if ( featureType == null ) { LOG.logDebug( "Feature type '" + ftName + "' is not defined in schema. Generating feature type dynamically." ); featureType = generateFeatureType( element ); } return featureType; } /** * Method to create a <code>FeatureType</code> from the child elements (properties) of the * given feature element. Used if no schema (=FeatureType definition) is available. * * @param element * feature element * @return the generated feature type. * @throws XMLParsingException */ private FeatureType generateFeatureType( Element element ) throws XMLParsingException { ElementList el = XMLTools.getChildElements( element ); ArrayList<PropertyType> propertyList = new ArrayList<PropertyType>( el.getLength() ); for ( int i = 0; i < el.getLength(); i++ ) { Element propertyElement = el.item( i ); QualifiedName propertyName = getQualifiedName( propertyElement ); if ( !propertyName.equals( PROP_NAME_BOUNDED_BY ) && !propertyName.equals( PROP_NAME_NAME ) && !propertyName.equals( PROP_NAME_DESCRIPTION ) ) { PropertyType propertyType = determinePropertyType( propertyElement, propertyName ); if ( !propertyList.contains( propertyType ) ) { propertyList.add( propertyType ); } } } PropertyType[] properties = new PropertyType[propertyList.size()]; properties = propertyList.toArray( properties ); QualifiedName ftName = getQualifiedName( element ); FeatureType featureType = FeatureFactory.createFeatureType( ftName, false, properties ); return featureType; } /** * Determines the property type for the given property element heuristically. * * @param propertyElement * property element * @param propertyName * qualified name of the property element * @return the property type. * @throws XMLParsingException */ private PropertyType determinePropertyType( Element propertyElement, QualifiedName propertyName ) throws XMLParsingException { PropertyType propertyType = null; ElementList childList = XMLTools.getChildElements( propertyElement ); // xlink attr present -> feature property Attr xlink = (Attr) XMLTools.getNode( propertyElement, "@xlink:href", nsContext ); if ( childList.getLength() == 0 && xlink == null ) { // no child elements -> simple property String value = XMLTools.getStringValue( propertyElement ); if ( value != null ) { value = value.trim(); } propertyType = guessSimplePropertyType( value, propertyName ); } else { // geometry or feature property if ( xlink != null ) { // TODO could be xlinked geometry as well propertyType = FeatureFactory.createFeaturePropertyType( propertyName, 0, -1 ); } else { QualifiedName elementName = getQualifiedName( childList.item( 0 ) ); if ( isGeometry( elementName ) ) { propertyType = FeatureFactory.createGeometryPropertyType( propertyName, elementName, 0, -1 ); } else { // feature property propertyType = FeatureFactory.createFeaturePropertyType( propertyName, 0, -1 ); } } } return propertyType; } /** * Heuristically determines the simple property type from the given property value. * <p> * NOTE: This method may produce unwanted results, for example if an "xsd:string" property * contains a value that can be parsed as an integer, it is always determined as a numeric * property. * * @param value * string value to be used to determine property type * @param propertyName * name of the property * @return the simple property type. */ private SimplePropertyType guessSimplePropertyType( String value, QualifiedName propertyName ) { int typeCode = Types.VARCHAR; if ( this.guessSimpleTypes ) { // parseable as integer? try { Integer.parseInt( value ); typeCode = Types.INTEGER; } catch ( NumberFormatException e ) { // so it's not an integer } // parseable as double? if ( typeCode == Types.VARCHAR ) { try { Double.parseDouble( value ); typeCode = Types.NUMERIC; } catch ( NumberFormatException e ) { // so it's not a double } } // parseable as ISO date? /* if (typeCode == Types.VARCHAR) { try { TimeTools.createCalendar( value ); typeCode = Types.DATE; } catch (Exception e) {} } */ } SimplePropertyType propertyType = FeatureFactory.createSimplePropertyType( propertyName, typeCode, 0, -1 ); return propertyType; } /** * Returns true if the given element name is a known GML geometry. * * @param elementName * @return true if the given element name is a known GML geometry, false otherwise. */ private boolean isGeometry( QualifiedName elementName ) { boolean isGeometry = false; if ( TYPE_NAME_BOX.equals( elementName ) || TYPE_NAME_LINESTRING.equals( elementName ) || TYPE_NAME_MULTIGEOMETRY.equals( elementName ) || TYPE_NAME_MULTILINESTRING.equals( elementName ) || TYPE_NAME_MULTIPOINT.equals( elementName ) || TYPE_NAME_MULTIPOLYGON.equals( elementName ) || TYPE_NAME_POINT.equals( elementName ) || TYPE_NAME_POLYGON.equals( elementName ) || TYPE_NAME_SURFACE.equals( elementName ) || TYPE_NAME_MULTISURFACE.equals( elementName ) || TYPE_NAME_CURVE.equals( elementName ) || TYPE_NAME_MULTICURVE.equals( elementName ) ) { isGeometry = true; } return isGeometry; } } /* ******************************************************************** Changes to this class. What the people have been up to: $Log: GMLFeatureDocument.java,v $ Revision 1.32 2006/11/27 09:07:52 poth JNI integration of proj4 has been removed. The CRS functionality now will be done by native deegree code. Revision 1.31 2006/08/31 15:21:41 mschneider Javadoc improvements. Revision 1.30 2006/08/31 15:00:26 mschneider Added second constructor that allows to disable the guessing of simple types. Javadoc fixes. Revision 1.29 2006/08/21 15:47:59 mschneider Refactored due to cleanup (and splitting) of org.deegree.io.datastore.schema package. Revision 1.28 2006/08/01 10:41:42 mschneider Added handling of empty fids (""). Revision 1.27 2006/07/25 15:54:43 mschneider Activated check for multiple features with same id in the document. Revision 1.26 2006/07/25 14:46:21 mschneider Javadoc corrections. Revision 1.25 2006/05/23 22:39:46 mschneider Fixed error message. Revision 1.24 2006/05/23 16:07:28 mschneider Changed visibility of parseProperty( Element propertyElement, FeatureType featureType ) to public. Revision 1.23 2006/05/03 17:26:40 poth *** empty log message *** Revision 1.22 2006/05/02 17:32:04 poth *** empty log message *** Revision 1.21 2006/04/27 09:44:59 poth *** empty log message *** Revision 1.20 2006/04/26 16:19:37 mschneider Synchronized createSimpleProperty() with AbstractSQLDatastore.convertToSQLType(). Revision 1.19 2006/04/06 20:25:27 poth *** empty log message *** Revision 1.18 2006/04/04 20:39:42 poth *** empty log message *** Revision 1.17 2006/04/04 17:51:55 mschneider Fixed imports. Revision 1.16 2006/04/04 10:32:11 mschneider Adapted to XMLSchemaException changes. Revision 1.15 2006/03/31 08:13:13 poth *** empty log message *** Revision 1.14 2006/03/30 21:20:26 poth *** empty log message *** Revision 1.13 2006/03/21 13:23:56 poth *** empty log message *** Revision 1.12 2006/03/03 13:36:50 mschneider Added handling of Floats. Improved error messages. Revision 1.11 2006/03/02 18:03:51 poth *** empty log message *** Revision 1.10 2006/02/23 15:30:41 mschneider Added hack to work around empty properties. Revision 1.9 2006/02/21 19:47:49 poth *** empty log message *** Revision 1.8 2006/02/05 18:52:49 mschneider Cleanup. Revision 1.7 2006/02/04 22:50:48 mschneider Added setSchemas() to explicitly specify the application schemas for this document. Revision 1.6 2006/01/31 16:24:43 mschneider Changes due to refactoring of org.deegree.model.feature package. Revision 1.5 2006/01/30 16:21:03 mschneider Moved resolveXLinkReferences() here. Revision 1.4 2006/01/24 16:13:17 poth *** empty log message *** Revision 1.3 2006/01/23 10:25:40 mschneider Added heuristic for determining Integer / Double / Date property types. Fixed handling of String property values. Revision 1.2 2006/01/20 18:13:47 mschneider Moved parsing functionality from GMLFeatureAdapter here. Revision 1.1 2006/01/19 16:18:14 mschneider Initial version. ********************************************************************** */