/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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. */ package org.geotools.gml3.bindings; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import org.geotools.feature.FeatureImpl; import org.geotools.feature.NameImpl; import org.geotools.feature.type.FeatureTypeImpl; import org.geotools.gml3.GML; import org.geotools.gml3.XSDIdRegistry; import org.geotools.util.Converters; import org.geotools.xlink.XLINK; import org.geotools.xml.AbstractComplexBinding; import org.geotools.xml.ElementInstance; import org.geotools.xml.Node; import org.opengis.feature.ComplexAttribute; import org.opengis.feature.Feature; import org.opengis.feature.Property; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.type.Name; import org.opengis.filter.identity.Identifier; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.Attributes; /** * Binding object for the type http://www.opengis.net/gml:FeaturePropertyType. * * <p> * <pre> * <code> * <complexType name="FeaturePropertyType"> * <annotation> * <documentation>Container for a feature - follow gml:AssociationType pattern.</documentation> * </annotation> * <sequence minOccurs="0"> * <element ref="gml:_Feature"/> * </sequence> * <attributeGroup ref="gml:AssociationAttributeGroup"/> * </complexType> * * </code> * </pre> * </p> * * * * @source $URL$ */ public class FeaturePropertyTypeBinding extends AbstractComplexBinding { /** * id set in the document, used to check against duplicate gml:id. If an gml:id is already * encoded for an featureMember, the next occurrence will be encoded with xlink:href */ private XSDIdRegistry idSet; public FeaturePropertyTypeBinding(XSDIdRegistry idSet) { super(); this.idSet = idSet; } /** * @generated */ public QName getTarget() { return GML.FeaturePropertyType; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * * @generated modifiable */ public Class getType() { return Feature.class; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * * @generated modifiable */ public Object parse(ElementInstance instance, Node node, Object value) throws Exception { return node.getChildValue(Feature.class); } @Override public Object getProperty(Object object, QName name) throws Exception { if (GML._Feature.equals(name)) { if (object instanceof SimpleFeature) { return object; } else if (object instanceof FeatureImpl) { ComplexAttribute complex = (ComplexAttribute) object; Identifier ident = complex.getIdentifier(); if (ident == null) { return object; } String id = Converters.convert(ident.getID(), String.class); if (idSet.idExists(id)) { return null; } return object; } else if (object instanceof ComplexAttribute) { return ((ComplexAttribute) object).getProperties().iterator().next(); } } return null; } /** * @see org.geotools.xml.AbstractComplexBinding#encode(java.lang.Object, org.w3c.dom.Document, * org.w3c.dom.Element) */ @Override public Element encode(Object object, Document document, Element value) throws Exception { if (object instanceof ComplexAttribute) { ComplexAttribute complex = (ComplexAttribute) object; checkXlinkHref(complex); GML3EncodingUtils.encodeClientProperties(complex, value); GML3EncodingUtils.encodeSimpleContent(complex, document, value); } return value; } /** * Check if the complex attribute contains a feature which id is pre-existing in the document. * If it's true, make sure it's only encoded as an xlink:href to the existing id. * * @param value * The complex attribute value * @param att * The complex attribute itself */ private void checkXlinkHref(ComplexAttribute att) { Identifier ident = att.getIdentifier(); if (ident == null) { return; } String id = Converters.convert(ident.getID(), String.class); if (idSet.idExists(id)) { // XSD type ids can only appear once in the same document, otherwise the document is // not schema valid. Attributes of the same ids should be encoded as xlink:href to // the existing attribute. Object clientProperties = att.getUserData().get(Attributes.class); Map<Name, Object> map = null; if (clientProperties == null) { map = new HashMap<Name, Object>(); att.getUserData().put(Attributes.class, map); } else { map = (Map<Name, Object>) clientProperties; } map.put(toTypeName(XLINK.HREF), "#" + id.toString()); // make sure the value is not encoded att.setValue(Collections.emptyList()); } return; } /** * Convert a {@link QName} to a {@link Name}. * * @param name * @return */ private static Name toTypeName(QName name) { if (XMLConstants.NULL_NS_URI.equals(name.getNamespaceURI())) { return new NameImpl(name.getLocalPart()); } else { return new NameImpl(name.getNamespaceURI(), name.getLocalPart()); } } }