001 //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/src/org/deegree/ogcwebservices/wfs/XMLFactory.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.ogcwebservices.wfs; 037 038 import static org.deegree.framework.xml.XMLTools.appendElement; 039 import static org.deegree.ogcbase.CommonNamespaces.OGC_PREFIX; 040 import static org.deegree.ogcbase.CommonNamespaces.WFSNS; 041 import static org.deegree.ogcbase.CommonNamespaces.WFS_PREFIX; 042 043 import java.io.IOException; 044 import java.io.StringReader; 045 import java.net.URI; 046 import java.util.Collection; 047 import java.util.HashSet; 048 import java.util.Iterator; 049 import java.util.List; 050 import java.util.Map; 051 052 import org.deegree.datatypes.QualifiedName; 053 import org.deegree.framework.log.ILogger; 054 import org.deegree.framework.log.LoggerFactory; 055 import org.deegree.framework.util.StringTools; 056 import org.deegree.framework.xml.XMLException; 057 import org.deegree.framework.xml.XMLParsingException; 058 import org.deegree.framework.xml.XMLTools; 059 import org.deegree.io.datastore.FeatureId; 060 import org.deegree.model.feature.Feature; 061 import org.deegree.model.feature.FeatureException; 062 import org.deegree.model.feature.FeatureProperty; 063 import org.deegree.model.feature.GMLFeatureAdapter; 064 import org.deegree.model.filterencoding.Filter; 065 import org.deegree.model.filterencoding.Function; 066 import org.deegree.model.filterencoding.capabilities.FilterCapabilities; 067 import org.deegree.model.metadata.iso19115.Keywords; 068 import org.deegree.model.spatialschema.Envelope; 069 import org.deegree.model.spatialschema.Geometry; 070 import org.deegree.model.spatialschema.GeometryException; 071 import org.deegree.ogcbase.CommonNamespaces; 072 import org.deegree.ogcbase.PropertyPath; 073 import org.deegree.ogcbase.SortProperty; 074 import org.deegree.ogcbase.XLinkPropertyPath; 075 import org.deegree.ogcwebservices.getcapabilities.Contents; 076 import org.deegree.ogcwebservices.getcapabilities.MetadataURL; 077 import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata; 078 import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification; 079 import org.deegree.ogcwebservices.getcapabilities.ServiceProvider; 080 import org.deegree.ogcwebservices.wfs.capabilities.FeatureTypeList; 081 import org.deegree.ogcwebservices.wfs.capabilities.FormatType; 082 import org.deegree.ogcwebservices.wfs.capabilities.GMLObject; 083 import org.deegree.ogcwebservices.wfs.capabilities.Operation; 084 import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities; 085 import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument; 086 import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType; 087 import org.deegree.ogcwebservices.wfs.operation.GetFeature; 088 import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument; 089 import org.deegree.ogcwebservices.wfs.operation.Lock; 090 import org.deegree.ogcwebservices.wfs.operation.LockFeature; 091 import org.deegree.ogcwebservices.wfs.operation.LockFeatureDocument; 092 import org.deegree.ogcwebservices.wfs.operation.LockFeatureResponse; 093 import org.deegree.ogcwebservices.wfs.operation.LockFeatureResponseDocument; 094 import org.deegree.ogcwebservices.wfs.operation.Query; 095 import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE; 096 import org.deegree.ogcwebservices.wfs.operation.transaction.Delete; 097 import org.deegree.ogcwebservices.wfs.operation.transaction.Insert; 098 import org.deegree.ogcwebservices.wfs.operation.transaction.InsertResults; 099 import org.deegree.ogcwebservices.wfs.operation.transaction.Transaction; 100 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionDocument; 101 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation; 102 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse; 103 import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponseDocument; 104 import org.deegree.ogcwebservices.wfs.operation.transaction.Update; 105 import org.w3c.dom.Comment; 106 import org.w3c.dom.Document; 107 import org.w3c.dom.Element; 108 import org.xml.sax.SAXException; 109 110 /** 111 * Responsible for the generation of XML representations of objects from the WFS context. 112 * 113 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a> 114 * @author last edited by: $Author: mschneider $ 115 * 116 * @version $Revision: 18281 $, $Date: 2009-06-29 15:07:08 +0200 (Mo, 29 Jun 2009) $ 117 */ 118 public class XMLFactory extends org.deegree.owscommon.XMLFactory { 119 120 private static final URI WFS = CommonNamespaces.WFSNS; 121 122 private static final URI OGCNS = CommonNamespaces.OGCNS; 123 124 // private static final String PRE_WFS = CommonNamespaces.WFS_PREFIX + ":"; 125 126 private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class ); 127 128 /** 129 * Exports a <code>WFSCapabilities</code> instance to a <code>WFSCapabilitiesDocument</code>. 130 * 131 * @param capabilities 132 * @return DOM representation of the <code>WFSCapabilities</code> 133 * @throws IOException 134 * if XML template could not be loaded 135 */ 136 public static WFSCapabilitiesDocument export( WFSCapabilities capabilities ) 137 throws IOException { 138 return export( capabilities, true, true, true, true ); 139 } 140 141 /** 142 * Exports a <code>WFSCapabilities</code> instance to a <code>WFSCapabilitiesDocument</code>. 143 * 144 * @param capabilities 145 * @param sections 146 * names of sections to be exported, may contain 'All' 147 * @return DOM representation of the <code>WFSCapabilities</code> 148 * @throws IOException 149 * if XML template could not be loaded 150 */ 151 public static WFSCapabilitiesDocument export( WFSCapabilities capabilities, String[] sections ) 152 throws IOException { 153 154 if ( sections == null || sections.length == 0 ) { 155 return export( capabilities ); 156 } 157 158 if ( sections.length == 1 && sections[0].equalsIgnoreCase( "all" ) ) { 159 return export( capabilities ); 160 } 161 162 boolean ident = false, provider = false, md = false, ftlist = false; 163 164 HashSet<String> set = new HashSet<String>(); 165 for ( String s : sections ) { 166 set.add( s.toLowerCase() ); 167 } 168 169 LOG.logDebug( "The set of requested sections was", set ); 170 171 if ( set.contains( "serviceidentification" ) ) { 172 ident = true; 173 } 174 if ( set.contains( "serviceprovider" ) ) { 175 provider = true; 176 } 177 if ( set.contains( "operationsmetadata" ) ) { 178 md = true; 179 } 180 if ( set.contains( "featuretypelist" ) ) { 181 ftlist = true; 182 } 183 184 return export( capabilities, ident, provider, md, ftlist ); 185 } 186 187 /** 188 * @param capabilities 189 * @param serviceIdentification 190 * @param serviceProvider 191 * @param operationsMetadata 192 * @param featureTypeList 193 * @return the exported capabilities document (possibly missing some sections if one of the flags was set to false) 194 * @throws IOException 195 */ 196 public static WFSCapabilitiesDocument export( WFSCapabilities capabilities, boolean serviceIdentification, 197 boolean serviceProvider, boolean operationsMetadata, 198 boolean featureTypeList ) 199 throws IOException { 200 WFSCapabilitiesDocument capabilitiesDocument = new WFSCapabilitiesDocument(); 201 202 try { 203 capabilitiesDocument.createEmptyDocument(); 204 Element root = capabilitiesDocument.getRootElement(); 205 206 root.setAttribute( "updateSequence", capabilities.getUpdateSequence() ); 207 208 if ( serviceIdentification ) { 209 ServiceIdentification si = capabilities.getServiceIdentification(); 210 if ( si != null ) { 211 appendServiceIdentification( root, si ); 212 } 213 } 214 215 if ( serviceProvider ) { 216 ServiceProvider sp = capabilities.getServiceProvider(); 217 if ( sp != null ) { 218 appendServiceProvider( root, sp ); 219 } 220 } 221 222 if ( operationsMetadata ) { 223 OperationsMetadata om = capabilities.getOperationsMetadata(); 224 if ( om != null ) { 225 appendOperationsMetadata( root, om ); 226 } 227 } 228 229 if ( featureTypeList ) { 230 FeatureTypeList ftl = capabilities.getFeatureTypeList(); 231 if ( ftl != null ) { 232 appendFeatureTypeList( root, ftl ); 233 } 234 } 235 236 GMLObject[] servesGMLObjectTypes = capabilities.getServesGMLObjectTypeList(); 237 if ( servesGMLObjectTypes != null ) { 238 appendGMLObjectTypeList( root, WFS, "ServesGMLObjectTypeList", servesGMLObjectTypes ); 239 } 240 GMLObject[] supportsGMLObjectTypes = capabilities.getSupportsGMLObjectTypeList(); 241 if ( supportsGMLObjectTypes != null ) { 242 appendGMLObjectTypeList( root, WFS, "SupportsGMLObjectTypeList", supportsGMLObjectTypes ); 243 } 244 Contents contents = capabilities.getContents(); 245 if ( contents != null ) { 246 // appendContents(root, contents); 247 } 248 249 FilterCapabilities fc = capabilities.getFilterCapabilities(); 250 if ( fc != null ) { 251 org.deegree.model.filterencoding.XMLFactory.appendFilterCapabilities110( root, fc ); 252 } 253 254 } catch ( SAXException e ) { 255 LOG.logError( e.getMessage(), e ); 256 } 257 return capabilitiesDocument; 258 } 259 260 /** 261 * Appends the DOM representation of the {@link ServiceIdentification} section to the passed {@link Element}. 262 * 263 * @param root 264 * @param serviceIdentification 265 */ 266 protected static void appendServiceIdentification( Element root, ServiceIdentification serviceIdentification ) { 267 268 // 'ServiceIdentification'-element 269 Element serviceIdentificationNode = XMLTools.appendElement( root, OWSNS, "ows:ServiceIdentification" ); 270 271 // the optional title element 272 String tmp = serviceIdentification.getTitle(); 273 if ( tmp != null && !"".equals( tmp ) ) { 274 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Title", tmp ); 275 } 276 277 // the optional abstract element 278 tmp = serviceIdentification.getAbstract(); 279 if ( tmp != null && !"".equals( tmp ) ) { 280 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Abstract", tmp ); 281 } 282 283 // the optional keywords element 284 appendKeywords( serviceIdentificationNode, serviceIdentification.getKeywords(), OWSNS ); 285 286 // 'ServiceType'-element 287 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceType", 288 serviceIdentification.getServiceType().getCode() ); 289 290 // 'ServiceTypeVersion'-elements 291 String[] versions = serviceIdentification.getServiceTypeVersions(); 292 for ( int i = 0; i < versions.length; i++ ) { 293 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:ServiceTypeVersion", versions[i] ); 294 } 295 296 // 'Fees'-element 297 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:Fees", serviceIdentification.getFees() ); 298 299 // 'AccessConstraints'-element 300 String[] constraints = serviceIdentification.getAccessConstraints(); 301 if ( constraints != null ) { 302 for ( int i = 0; i < constraints.length; i++ ) { 303 XMLTools.appendElement( serviceIdentificationNode, OWSNS, "ows:AccessConstraints", constraints[i] ); 304 } 305 } 306 } 307 308 /** 309 * Appends a <code>ows:Keywords</code> -element for each <code>Keywords</code> object of the passed array to the 310 * passed <code>Element</code>. 311 * 312 * @param xmlNode 313 * @param keywords 314 * @param namespaceURI 315 */ 316 protected static void appendKeywords( Element xmlNode, Keywords[] keywords, URI namespaceURI ) { 317 if ( keywords != null ) { 318 for ( int i = 0; i < keywords.length; i++ ) { 319 Element node = XMLTools.appendElement( xmlNode, namespaceURI, "ows:Keywords" ); 320 appendKeywords( node, keywords[i], namespaceURI ); 321 } 322 } 323 } 324 325 /** 326 * Appends a <code>Keyword</code> -element to the passed <code>Element</code> and fills it with the available 327 * keywords. 328 * 329 * @param xmlNode 330 * @param keywords 331 * @param namespaceURI 332 */ 333 protected static void appendKeywords( Element xmlNode, Keywords keywords, URI namespaceURI ) { 334 if ( keywords != null ) { 335 String[] kw = keywords.getKeywords(); 336 for ( int i = 0; i < kw.length; i++ ) { 337 XMLTools.appendElement( xmlNode, namespaceURI, "ows:Keyword", kw[i] ); 338 } 339 if ( keywords.getThesaurusName() != null ) { 340 XMLTools.appendElement( xmlNode, namespaceURI, "ows:Type", keywords.getThesaurusName() ); 341 } 342 } 343 } 344 345 /** 346 * Exports a <code>GetFeature</code> instance to a <code>GetFeatureDocument</code>. 347 * 348 * @param getFeature 349 * request to be exported 350 * @return XML representation of the <code>GetFeature</code> request 351 * @throws IOException 352 * @throws XMLParsingException 353 */ 354 public static GetFeatureDocument export( GetFeature getFeature ) 355 throws IOException, XMLParsingException { 356 357 GetFeatureDocument xml = new GetFeatureDocument(); 358 try { 359 xml.load( XMLFactory.class.getResource( "GetFeatureTemplate.xml" ) ); 360 } catch ( SAXException e ) { 361 throw new XMLParsingException( "could not parse GetFeatureTemplate.xml", e ); 362 } 363 Element root = xml.getRootElement(); 364 root.setAttribute( "outputFormat", getFeature.getOutputFormat() ); 365 root.setAttribute( "service", "WFS" ); 366 root.setAttribute( "version", getFeature.getVersion() ); 367 if ( getFeature.getHandle() != null ) { 368 root.setAttribute( "handle", getFeature.getHandle() ); 369 } 370 if ( getFeature.getResultType() == RESULT_TYPE.HITS ) { 371 root.setAttribute( "resultType", "hits" ); 372 } else { 373 root.setAttribute( "resultType", "results" ); 374 } 375 if ( getFeature.getMaxFeatures() > 0 ) { 376 root.setAttribute( "maxFeatures", "" + getFeature.getMaxFeatures() ); 377 } 378 if ( getFeature.getStartPosition() > 0 ) { 379 root.setAttribute( "startPosition", "" + getFeature.getStartPosition() ); 380 } 381 if ( getFeature.getTraverseXLinkDepth() >= 0 ) { 382 root.setAttribute( "traverseXlinkDepth", "" + getFeature.getTraverseXLinkDepth() ); 383 } 384 if ( getFeature.getTraverseXLinkExpiry() >= 0 ) { 385 root.setAttribute( "traverseXlinkExpiry", "" + getFeature.getTraverseXLinkExpiry() ); 386 } 387 Query[] queries = getFeature.getQuery(); 388 for ( int i = 0; i < queries.length; i++ ) { 389 appendQuery( root, queries[i] ); 390 } 391 return xml; 392 } 393 394 /** 395 * Exports a {@link LockFeature} request instance to a {@link LockFeatureDocument}. 396 * 397 * @param request 398 * request to be exported 399 * @return XML representation of the <code>LockFeature</code> request 400 * @throws IOException 401 * @throws XMLParsingException 402 * @throws SAXException 403 */ 404 public static LockFeatureDocument export( LockFeature request ) 405 throws IOException, XMLParsingException, SAXException { 406 407 LockFeatureDocument doc = new LockFeatureDocument(); 408 doc.createEmptyDocument(); 409 410 Element root = doc.getRootElement(); 411 root.setAttribute( "version", request.getVersion() ); 412 root.setAttribute( "service", "WFS" ); 413 if ( request.getHandle() != null ) { 414 root.setAttribute( "handle", request.getHandle() ); 415 } 416 root.setAttribute( "expiry", "" + request.getExpiry() ); 417 root.setAttribute( "lockAction", "" + request.getLockAction() ); 418 419 List<Lock> locks = request.getLocks(); 420 for ( Lock lock : locks ) { 421 appendLock( root, lock ); 422 } 423 return doc; 424 } 425 426 /** 427 * Appends the XML representation of the given {@link Lock} to the given element. 428 * 429 * @param root 430 * @param lock 431 */ 432 private static void appendLock( Element root, Lock lock ) 433 throws IOException, XMLParsingException { 434 435 Element lockElement = XMLTools.appendElement( root, WFS, "Lock" ); 436 if ( lock.getHandle() != null ) { 437 lockElement.setAttribute( "handle", lock.getHandle() ); 438 } 439 QualifiedName typeName = lock.getTypeName(); 440 if ( typeName.getPrefix() != null ) { 441 lockElement.setAttribute( "xmlns:" + typeName.getPrefix(), typeName.getNamespace().toASCIIString() ); 442 } 443 lockElement.setAttribute( "typeName", typeName.getPrefixedName() ); 444 445 // copy filter into Lock element 446 if ( lock.getFilter() != null ) { 447 StringReader sr = new StringReader( lock.getFilter().to110XML().toString() ); 448 Document doc; 449 try { 450 doc = XMLTools.parse( sr ); 451 } catch ( SAXException e ) { 452 throw new XMLParsingException( "Could not parse filter.", e ); 453 } 454 Element elem = XMLTools.appendElement( lockElement, OGCNS, "ogc:Filter" ); 455 XMLTools.copyNode( doc.getDocumentElement(), elem ); 456 } 457 } 458 459 /** 460 * Exports a {@link LockFeatureResponse} instance to its XML representation. 461 * 462 * @param response 463 * response to be exported 464 * @return XML representation of the <code>LockFeatureResponse</code> 465 * @throws IOException 466 * @throws SAXException 467 */ 468 public static LockFeatureResponseDocument export( LockFeatureResponse response ) 469 throws IOException, SAXException { 470 471 LockFeatureResponseDocument doc = new LockFeatureResponseDocument(); 472 doc.createEmptyDocument(); 473 474 Element root = doc.getRootElement(); 475 XMLTools.appendElement( root, WFS, "LockId", response.getLockId() ); 476 String[] fids = response.getFeaturesLocked(); 477 if ( fids.length != 0 ) { 478 Element featuresLockedElement = XMLTools.appendElement( root, WFS, "FeaturesLocked" ); 479 for ( String fid : fids ) { 480 appendFeatureId( featuresLockedElement, fid ); 481 } 482 } 483 fids = response.getFeaturesNotLocked(); 484 if ( fids.length != 0 ) { 485 Element featuresNotLockedElement = XMLTools.appendElement( root, WFS, "FeaturesNotLocked" ); 486 for ( String fid : fids ) { 487 appendFeatureId( featuresNotLockedElement, fid ); 488 } 489 } 490 return doc; 491 } 492 493 /** 494 * Exports a {@link Transaction} instance to its XML representation. 495 * 496 * @param transaction 497 * transaction to export 498 * @return XML representation of transaction 499 * @throws IOException 500 * @throws XMLParsingException 501 */ 502 public static TransactionDocument export( Transaction transaction ) 503 throws IOException, XMLParsingException { 504 505 TransactionDocument xml = new TransactionDocument(); 506 try { 507 xml.createEmptyDocument(); 508 } catch ( SAXException e ) { 509 throw new IOException( e.getMessage() ); 510 } 511 Element root = xml.getRootElement(); 512 List<TransactionOperation> ops = transaction.getOperations(); 513 for ( int i = 0; i < ops.size(); i++ ) { 514 try { 515 if ( ops.get( i ) instanceof Insert ) { 516 appendInsert( root, (Insert) ops.get( i ) ); 517 } else if ( ops.get( i ) instanceof Update ) { 518 appendUpdate( root, (Update) ops.get( i ) ); 519 } else if ( ops.get( i ) instanceof Delete ) { 520 appendDelete( root, (Delete) ops.get( i ) ); 521 } 522 } catch ( Exception e ) { 523 LOG.logError( e.getMessage(), e ); 524 throw new XMLParsingException( e.getMessage() ); 525 } 526 } 527 return xml; 528 } 529 530 /** 531 * Adds the XML representation of a <code>Delete</code> operation to the given element. 532 * 533 * @param root 534 * @param delete 535 */ 536 private static void appendDelete( Element root, Delete delete ) { 537 Element el = XMLTools.appendElement( root, WFS, "Delete" ); 538 if ( delete.getHandle() != null ) { 539 el.setAttribute( "handle", delete.getHandle() ); 540 } 541 el.setAttribute( "typeName", delete.getTypeName().getPrefixedName() ); 542 // ensure that the type's namespace is declared 543 el.setAttribute( "xmlns:" + delete.getTypeName().getPrefix(), 544 delete.getTypeName().getNamespace().toASCIIString() ); 545 546 Filter filter = delete.getFilter(); 547 if ( filter != null ) { 548 org.deegree.model.filterencoding.XMLFactory.appendFilter( el, filter ); 549 } 550 root.appendChild( el ); 551 } 552 553 /** 554 * Adds the XML representation of an <code>Update</code> operation to the given element. 555 * <p> 556 * Respects the deegree-specific extension to the Update operation: instead of specifying properties and their 557 * values, it's also possible to only specify just one feature that replaces the matched feature. 558 * 559 * @param root 560 * @param update 561 * @throws SAXException 562 * @throws IOException 563 * @throws FeatureException 564 * @throws GeometryException 565 */ 566 private static void appendUpdate( Element root, Update update ) 567 throws FeatureException, IOException, SAXException, GeometryException { 568 569 Element el = XMLTools.appendElement( root, WFS, "Update" ); 570 if ( update.getHandle() != null ) { 571 el.setAttribute( "handle", update.getHandle() ); 572 } 573 574 el.setAttribute( "typeName", update.getTypeName().getPrefixedName() ); 575 576 // ensure that the type's namespace is declared 577 el.setAttribute( "xmlns:" + update.getTypeName().getPrefix(), 578 update.getTypeName().getNamespace().toASCIIString() ); 579 580 Feature replacement = update.getFeature(); 581 if ( replacement != null ) { 582 GMLFeatureAdapter adapter = new GMLFeatureAdapter(); 583 adapter.append( el, replacement ); 584 } else { 585 Map<PropertyPath, FeatureProperty> replaces = update.getReplacementProperties(); 586 for ( PropertyPath propertyName : replaces.keySet() ) { 587 Element propElement = XMLTools.appendElement( el, WFS, "Property" ); 588 Element nameElement = XMLTools.appendElement( propElement, WFS, "Name" ); 589 org.deegree.ogcbase.XMLFactory.appendPropertyPath( nameElement, propertyName ); 590 591 // append property value 592 Object propValue = replaces.get( propertyName ).getValue(); 593 if ( propValue != null ) { 594 Element valueElement = XMLTools.appendElement( propElement, WFS, "Value" ); 595 if ( propValue instanceof Feature ) { 596 GMLFeatureAdapter adapter = new GMLFeatureAdapter(); 597 adapter.append( valueElement, (Feature) propValue ); 598 } else if ( propValue instanceof Geometry ) { 599 appendGeometry( valueElement, (Geometry) propValue ); 600 } else { 601 XMLTools.setNodeValue( valueElement, propValue.toString() ); 602 } 603 } 604 } 605 } 606 607 Filter filter = update.getFilter(); 608 if ( filter != null ) { 609 org.deegree.model.filterencoding.XMLFactory.appendFilter( el, filter ); 610 } 611 root.appendChild( el ); 612 } 613 614 /** 615 * Adds the XML representation of an <code>Insert</code> operation to the given element. 616 * 617 * @param root 618 * @param insert 619 * @throws SAXException 620 * @throws IOException 621 * @throws FeatureException 622 */ 623 private static void appendInsert( Element root, Insert insert ) 624 throws IOException, FeatureException, XMLException, SAXException { 625 626 Element el = XMLTools.appendElement( root, WFS, "Insert" ); 627 if ( insert.getHandle() != null ) { 628 el.setAttribute( "handle", insert.getHandle() ); 629 } 630 if ( insert.getIdGen() != null ) { 631 switch ( insert.getIdGen() ) { 632 case USE_EXISTING: 633 el.setAttribute( "idgen", "UseExisting" ); 634 break; 635 case GENERATE_NEW: 636 el.setAttribute( "idgen", "GenerateNew" ); 637 break; 638 case REPLACE_DUPLICATE: 639 el.setAttribute( "idgen", "ReplaceDuplicate" ); 640 break; 641 } 642 } 643 644 GMLFeatureAdapter adapter = new GMLFeatureAdapter(); 645 adapter.append( el, insert.getFeatures() ); 646 } 647 648 /** 649 * Exports an instance of {@link TransactionResponse} to its XML representation. 650 * 651 * @param response 652 * TransactionResponse to export 653 * @return XML representation of TransactionResponse 654 * @throws IOException 655 */ 656 public static TransactionResponseDocument export( TransactionResponse response ) 657 throws IOException { 658 659 TransactionResponseDocument xml = new TransactionResponseDocument(); 660 try { 661 xml.createEmptyDocument(); 662 } catch ( SAXException e ) { 663 throw new IOException( e.getMessage() ); 664 } 665 666 Element root = xml.getRootElement(); 667 appendTransactionSummary( root, response.getTotalInserted(), response.getTotalUpdated(), 668 response.getTotalDeleted() ); 669 appendInsertResults( root, response.getInsertResults() ); 670 return xml; 671 } 672 673 /** 674 * Appends a 'wfs:TransactionSummary' element to the given element. 675 * 676 * @param root 677 * @param totalInserted 678 * @param totalUpdated 679 * @param totalDeleted 680 */ 681 private static void appendTransactionSummary( Element root, int totalInserted, int totalUpdated, int totalDeleted ) { 682 Element taSummary = XMLTools.appendElement( root, WFS, "TransactionSummary" ); 683 XMLTools.appendElement( taSummary, WFS, "totalInserted", "" + totalInserted ); 684 XMLTools.appendElement( taSummary, WFS, "totalUpdated", "" + totalUpdated ); 685 XMLTools.appendElement( taSummary, WFS, "totalDeleted", "" + totalDeleted ); 686 } 687 688 /** 689 * Appends an 'wfs:InsertResults' element to the given element (only if necessary). 690 * 691 * @param root 692 * @param insertResults 693 */ 694 private static void appendInsertResults( Element root, Collection<InsertResults> insertResults ) { 695 Element insertResultsElement = appendElement( root, WFS, "InsertResults" ); 696 697 // append synthetic ones because of the faulty schema 698 if ( insertResults.size() == 0 ) { 699 Document d = root.getOwnerDocument(); 700 Comment comment = d.createComment( "Dummy InsertResults element for compliance with (faulty?) WFS schema" ); 701 root.insertBefore( comment, insertResultsElement ); 702 Element elem = appendElement( insertResultsElement, WFS, "Feature" ); 703 appendElement( elem, OGCNS, OGC_PREFIX + ":FeatureId" ).setAttribute( "fid", "bogus" ); 704 } else { 705 Iterator<InsertResults> iter = insertResults.iterator(); 706 while ( iter.hasNext() ) { 707 appendFeatureIds( insertResultsElement, iter.next() ); 708 } 709 } 710 } 711 712 /** 713 * Appends a 'wfs:Feature' element to the given element. 714 * 715 * @param root 716 * @param results 717 */ 718 private static void appendFeatureIds( Element root, InsertResults results ) { 719 Element featureElement = XMLTools.appendElement( root, WFS, "Feature" ); 720 String handle = results.getHandle(); 721 if ( handle != null ) { 722 featureElement.setAttribute( "handle", handle ); 723 } 724 Iterator<FeatureId> iter = results.getFeatureIDs().iterator(); 725 while ( iter.hasNext() ) { 726 Element featureIdElement = XMLTools.appendElement( featureElement, OGCNS, "ogc:FeatureId" ); 727 featureIdElement.setAttribute( "fid", iter.next().getAsString() ); 728 } 729 } 730 731 /** 732 * Appends the XML representation of the given {@link Query} instance to an element. 733 * 734 * @param query 735 */ 736 private static void appendQuery( Element root, Query query ) 737 throws IOException, XMLParsingException { 738 739 Element queryElem = XMLTools.appendElement( root, WFS, "Query" ); 740 if ( query.getHandle() != null ) { 741 queryElem.setAttribute( "handle", query.getHandle() ); 742 } 743 if ( query.getFeatureVersion() != null ) { 744 queryElem.setAttribute( "featureVersion", query.getFeatureVersion() ); 745 } 746 QualifiedName[] qn = query.getTypeNames(); 747 String[] na = new String[qn.length]; 748 for ( int i = 0; i < na.length; i++ ) { 749 na[i] = qn[i].getPrefixedName(); 750 if ( qn[i].getNamespace() != null ) { 751 queryElem.setAttribute( "xmlns:" + qn[i].getPrefix(), qn[i].getNamespace().toASCIIString() ); 752 } 753 } 754 String tn = StringTools.arrayToString( na, ',' ); 755 queryElem.setAttribute( "typeName", tn ); 756 757 if ( query.getSrsName() != null ) { 758 queryElem.setAttribute( "srsName", query.getSrsName() ); 759 } 760 761 String[] aliases = query.getAliases(); 762 if ( aliases != null && aliases.length != 0 ) { 763 StringBuffer aliasesList = new StringBuffer( aliases[0] ); 764 for ( int i = 1; i < aliases.length; i++ ) { 765 aliasesList.append( ' ' ); 766 aliasesList.append( aliases[i] ); 767 } 768 queryElem.setAttribute( "aliases", aliasesList.toString() ); 769 } 770 771 PropertyPath[] propertyNames = query.getPropertyNames(); 772 for ( int i = 0; i < propertyNames.length; i++ ) { 773 if ( propertyNames[i] instanceof XLinkPropertyPath ) { 774 Element propertyNameElement = appendElement( queryElem, WFSNS, WFS_PREFIX + ":XlinkPropertyName" ); 775 String depth = Integer.toString( ( (XLinkPropertyPath) propertyNames[i] ).getXlinkDepth() ); 776 propertyNameElement.setAttribute( "traverseXlinkDepth", depth ); 777 appendPropertyPath( propertyNameElement, propertyNames[i] ); 778 } else { 779 Element propertyNameElement = appendElement( queryElem, WFSNS, WFS_PREFIX + ":PropertyName" ); 780 appendPropertyPath( propertyNameElement, propertyNames[i] ); 781 } 782 } 783 Function[] fn = query.getFunctions(); 784 // copy function definitions into query node 785 if ( fn != null ) { 786 for ( int i = 0; i < fn.length; i++ ) { 787 StringReader sr = new StringReader( fn[i].toXML().toString() ); 788 Document doc; 789 try { 790 doc = XMLTools.parse( sr ); 791 } catch ( SAXException e ) { 792 throw new XMLParsingException( "could not parse filter function", e ); 793 } 794 XMLTools.copyNode( doc.getDocumentElement(), queryElem ); 795 } 796 } 797 // copy filter into query node 798 if ( query.getFilter() != null ) { 799 StringReader sr = new StringReader( query.getFilter().to110XML().toString() ); 800 Document doc; 801 try { 802 doc = XMLTools.parse( sr ); 803 } catch ( SAXException e ) { 804 throw new XMLParsingException( "could not parse filter", e ); 805 } 806 Element elem = XMLTools.appendElement( queryElem, OGCNS, "ogc:Filter" ); 807 XMLTools.copyNode( doc.getDocumentElement(), elem ); 808 } 809 810 SortProperty[] sp = query.getSortProperties(); 811 if ( sp != null ) { 812 Element sortBy = XMLTools.appendElement( queryElem, OGCNS, "ogc:SortBy" ); 813 for ( int i = 0; i < sp.length; i++ ) { 814 Element sortProp = XMLTools.appendElement( sortBy, OGCNS, "ogc:SortProperty" ); 815 XMLTools.appendElement( sortProp, OGCNS, "ogc:PropertyName", sp[i].getSortProperty().getAsString() ); 816 if ( !sp[i].getSortOrder() ) { 817 XMLTools.appendElement( sortProp, OGCNS, "ogc:SortOrder", "DESC" ); 818 } 819 } 820 } 821 } 822 823 /** 824 * Appends the XML representation of the <code>wfs:FeatureTypeList</code>- section to the passed 825 * <code>Element</code>. 826 * 827 * @param root 828 * @param featureTypeList 829 */ 830 public static void appendFeatureTypeList( Element root, FeatureTypeList featureTypeList ) { 831 832 Element featureTypeListNode = XMLTools.appendElement( root, WFS, "FeatureTypeList", null ); 833 Operation[] operations = featureTypeList.getGlobalOperations(); 834 if ( operations != null ) { 835 Element operationsNode = XMLTools.appendElement( featureTypeListNode, WFS, "Operations" ); 836 for ( int i = 0; i < operations.length; i++ ) { 837 XMLTools.appendElement( operationsNode, WFS, "Operation", operations[i].getOperation() ); 838 } 839 } 840 WFSFeatureType[] featureTypes = featureTypeList.getFeatureTypes(); 841 if ( featureTypes != null ) { 842 for ( int i = 0; i < featureTypes.length; i++ ) { 843 appendWFSFeatureType( featureTypeListNode, featureTypes[i] ); 844 } 845 } 846 847 } 848 849 /** 850 * Appends the XML representation of the <code>WFSFeatureType</code> instance to the passed <code>Element</code>. 851 * 852 * @param root 853 * @param featureType 854 */ 855 public static void appendWFSFeatureType( Element root, WFSFeatureType featureType ) { 856 857 Element featureTypeNode = XMLTools.appendElement( root, WFS, "FeatureType" ); 858 859 if ( featureType.getName().getPrefix() != null ) { 860 XMLTools.appendNSBinding( featureTypeNode, featureType.getName().getPrefix(), 861 featureType.getName().getNamespace() ); 862 } 863 XMLTools.appendElement( featureTypeNode, WFS, "Name", featureType.getName().getPrefixedName() ); 864 XMLTools.appendElement( featureTypeNode, WFS, "Title", featureType.getTitle() ); 865 String abstract_ = featureType.getAbstract(); 866 if ( abstract_ != null ) { 867 XMLTools.appendElement( featureTypeNode, WFS, "Abstract", featureType.getAbstract() ); 868 } 869 Keywords[] keywords = featureType.getKeywords(); 870 if ( keywords != null ) { 871 appendOWSKeywords( featureTypeNode, keywords ); 872 } 873 URI defaultSrs = featureType.getDefaultSRS(); 874 if ( defaultSrs != null ) { 875 XMLTools.appendElement( featureTypeNode, WFS, "DefaultSRS", defaultSrs.toString() ); 876 URI[] otherSrs = featureType.getOtherSrs(); 877 if ( otherSrs != null ) { 878 for ( int i = 0; i < otherSrs.length; i++ ) { 879 XMLTools.appendElement( featureTypeNode, WFS, "OtherSRS", otherSrs[i].toString() ); 880 } 881 } 882 } else { 883 XMLTools.appendElement( featureTypeNode, WFS, "Title" ); 884 } 885 Operation[] operations = featureType.getOperations(); 886 if ( operations != null ) { 887 Element operationsNode = XMLTools.appendElement( featureTypeNode, WFS, "Operations" ); 888 for ( int i = 0; i < operations.length; i++ ) { 889 XMLTools.appendElement( operationsNode, WFS, "Operation", operations[i].getOperation() ); 890 } 891 } 892 FormatType[] formats = featureType.getOutputFormats(); 893 if ( formats != null ) { 894 appendOutputFormats( featureTypeNode, formats ); 895 } 896 Envelope[] wgs84BoundingBoxes = featureType.getWgs84BoundingBoxes(); 897 for ( int i = 0; i < wgs84BoundingBoxes.length; i++ ) { 898 appendWgs84BoundingBox( featureTypeNode, wgs84BoundingBoxes[i] ); 899 } 900 if ( featureType.getMetadataUrls() != null ) { 901 for ( MetadataURL metadataURL : featureType.getMetadataUrls() ) { 902 appendMetadataURL( featureTypeNode, metadataURL ); 903 } 904 } 905 } 906 907 /** 908 * Appends the XML representation of the <code>wfs:ServesGMLObjectTypeList</code>- section to the passed 909 * <code>Element</code> as a new element with the given qualified name. 910 * 911 * @param root 912 * @param elementNS 913 * @param elementName 914 * @param gmlObjectTypes 915 */ 916 public static void appendGMLObjectTypeList( Element root, URI elementNS, String elementName, 917 GMLObject[] gmlObjectTypes ) { 918 919 Element gmlObjectTypeListNode = XMLTools.appendElement( root, elementNS, elementName ); 920 for ( int i = 0; i < gmlObjectTypes.length; i++ ) { 921 appendGMLObjectTypeType( gmlObjectTypeListNode, gmlObjectTypes[i] ); 922 } 923 } 924 925 /** 926 * Appends the XML representation of the given {@link GMLObject} (as a <code>wfs:GMLObjectType</code> element) to 927 * the passed <code>Element</code>. 928 * 929 * @param root 930 * @param gmlObjectType 931 */ 932 public static void appendGMLObjectTypeType( Element root, GMLObject gmlObjectType ) { 933 934 Element gmlObjectTypeNode = XMLTools.appendElement( root, WFS, "GMLObjectType" ); 935 936 if ( gmlObjectType.getName().getPrefix() != null ) { 937 XMLTools.appendNSBinding( gmlObjectTypeNode, gmlObjectType.getName().getPrefix(), 938 gmlObjectType.getName().getNamespace() ); 939 } 940 XMLTools.appendElement( gmlObjectTypeNode, WFS, "Name", gmlObjectType.getName().getPrefixedName() ); 941 if ( gmlObjectType.getTitle() != null ) { 942 XMLTools.appendElement( gmlObjectTypeNode, WFS, "Title", gmlObjectType.getTitle() ); 943 } 944 String abstract_ = gmlObjectType.getAbstract(); 945 if ( abstract_ != null ) { 946 XMLTools.appendElement( gmlObjectTypeNode, WFS, "Abstract", gmlObjectType.getAbstract() ); 947 } 948 Keywords[] keywords = gmlObjectType.getKeywords(); 949 if ( keywords != null ) { 950 appendOWSKeywords( gmlObjectTypeNode, keywords ); 951 } 952 FormatType[] formats = gmlObjectType.getOutputFormats(); 953 if ( formats != null ) { 954 appendOutputFormats( gmlObjectTypeNode, formats ); 955 } 956 } 957 958 /** 959 * Appends the XML representation of the given {@link Envelope} (as an <code>ows:WGS84BoundingBoxType</code> 960 * element) to the passed <code>Element</code>. 961 * 962 * @param root 963 * @param envelope 964 */ 965 public static void appendWgs84BoundingBox( Element root, Envelope envelope ) { 966 Element wgs84BoundingBoxElement = XMLTools.appendElement( root, OWSNS, "ows:WGS84BoundingBox" ); 967 XMLTools.appendElement( wgs84BoundingBoxElement, OWSNS, "ows:LowerCorner", envelope.getMin().getX() + " " 968 + envelope.getMin().getY() ); 969 XMLTools.appendElement( wgs84BoundingBoxElement, OWSNS, "ows:UpperCorner", envelope.getMax().getX() + " " 970 + envelope.getMax().getY() ); 971 } 972 973 private static void appendMetadataURL( Element root, MetadataURL metadataURL ) { 974 Element metadataURLElement = XMLTools.appendElement( root, WFSNS, "wfs:MetadataURL", 975 metadataURL.getOnlineResource().toString() ); 976 metadataURLElement.setAttribute( "format", metadataURL.getFormat() ); 977 metadataURLElement.setAttribute( "type", metadataURL.getType() ); 978 } 979 980 /** 981 * Appends the XML representation of the given {@link FormatType}s as (as a <code>wfs:OutputFormats</code> element) 982 * to the passed <code>Element</code>. 983 * 984 * @param root 985 * @param formats 986 */ 987 public static void appendOutputFormats( Element root, FormatType[] formats ) { 988 989 Element outputFormatsNode = XMLTools.appendElement( root, WFS, "OutputFormats" ); 990 for ( int i = 0; i < formats.length; i++ ) { 991 appendElement( outputFormatsNode, WFS, "Format", formats[i].getValue() ); 992 } 993 } 994 }