001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wms/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.wms;
037    
038    import java.io.IOException;
039    import java.net.URL;
040    import java.util.List;
041    
042    import org.deegree.datatypes.QualifiedName;
043    import org.deegree.datatypes.values.TypedLiteral;
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.framework.util.StringTools;
047    import org.deegree.framework.xml.NamespaceContext;
048    import org.deegree.framework.xml.XMLParsingException;
049    import org.deegree.framework.xml.XMLTools;
050    import org.deegree.model.metadata.iso19115.Address;
051    import org.deegree.model.metadata.iso19115.Keywords;
052    import org.deegree.model.metadata.iso19115.OnlineResource;
053    import org.deegree.model.metadata.iso19115.Phone;
054    import org.deegree.model.spatialschema.Envelope;
055    import org.deegree.ogcbase.CommonNamespaces;
056    import org.deegree.ogcwebservices.OWSUtils;
057    import org.deegree.ogcwebservices.getcapabilities.MetadataURL;
058    import org.deegree.ogcwebservices.wms.capabilities.Attribution;
059    import org.deegree.ogcwebservices.wms.capabilities.AuthorityURL;
060    import org.deegree.ogcwebservices.wms.capabilities.DataURL;
061    import org.deegree.ogcwebservices.wms.capabilities.Dimension;
062    import org.deegree.ogcwebservices.wms.capabilities.Extent;
063    import org.deegree.ogcwebservices.wms.capabilities.FeatureListURL;
064    import org.deegree.ogcwebservices.wms.capabilities.Identifier;
065    import org.deegree.ogcwebservices.wms.capabilities.Layer;
066    import org.deegree.ogcwebservices.wms.capabilities.LayerBoundingBox;
067    import org.deegree.ogcwebservices.wms.capabilities.LegendURL;
068    import org.deegree.ogcwebservices.wms.capabilities.LogoURL;
069    import org.deegree.ogcwebservices.wms.capabilities.ScaleHint;
070    import org.deegree.ogcwebservices.wms.capabilities.Style;
071    import org.deegree.ogcwebservices.wms.capabilities.StyleSheetURL;
072    import org.deegree.ogcwebservices.wms.capabilities.StyleURL;
073    import org.deegree.ogcwebservices.wms.capabilities.UserDefinedSymbolization;
074    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities;
075    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilitiesDocument;
076    import org.deegree.ogcwebservices.wms.capabilities.WMSCapabilities_1_3_0;
077    import org.deegree.owscommon_new.DCP;
078    import org.deegree.owscommon_new.DomainType;
079    import org.deegree.owscommon_new.HTTP;
080    import org.deegree.owscommon_new.Operation;
081    import org.deegree.owscommon_new.OperationsMetadata;
082    import org.deegree.owscommon_new.ServiceIdentification;
083    import org.deegree.owscommon_new.ServiceProvider;
084    import org.w3c.dom.Element;
085    import org.xml.sax.SAXException;
086    
087    /**
088     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
089     * @author last edited by: $Author: mschneider $
090     *
091     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
092     */
093    public class XMLFactory extends org.deegree.owscommon.XMLFactory {
094    
095        private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class );
096    
097        private static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
098    
099        /**
100         * Exports a <code>WMSCapabilities</code> instance to a <code>WMSCapabilitiesDocument</code>.
101         *
102         * @param capabilities
103         * @return DOM representation of the <code>WMSCapabilities</code>
104         * @throws IOException
105         *             if XML template could not be loaded
106         */
107        public static WMSCapabilitiesDocument export( WMSCapabilities capabilities )
108                                throws IOException {
109    
110            // in case of a 1.3.0 capabilities, switch the method
111            if ( capabilities instanceof WMSCapabilities_1_3_0 ) {
112                return XMLFactory_1_3_0.export( (WMSCapabilities_1_3_0) capabilities );
113            }
114    
115            WMSCapabilitiesDocument capabilitiesDocument = new WMSCapabilitiesDocument();
116            try {
117                capabilitiesDocument.createEmptyDocument();
118                Element root = capabilitiesDocument.getRootElement();
119    
120                root.setAttribute( "version", "1.1.1" );
121                root.setAttribute( "updateSequence", capabilities.getUpdateSequence() );
122    
123                appendService( root, capabilities.getServiceIdentification(), capabilities.getServiceProvider() );
124    
125                appendCapabilityRequests( root, capabilities.getOperationMetadata() );
126    
127                appendUserDefinedSymbolization( (Element) XMLTools.getNode( root, "./Capability", nsContext ),
128                                                capabilities.getUserDefinedSymbolization() );
129    
130                appendCapabilityLayer( (Element) XMLTools.getNode( root, "./Capability", nsContext ),
131                                       capabilities.getLayer() );
132    
133                Element exc = XMLTools.getRequiredElement( root, "Capability/Exception", nsContext );
134                for ( String f : capabilities.getExceptions() ) {
135                    XMLTools.appendElement( exc, null, "Format", f );
136                }
137    
138            } catch ( SAXException e ) {
139                LOG.logError( e.getMessage(), e );
140            } catch ( XMLParsingException e ) {
141                LOG.logError( e.getMessage(), e );
142            }
143    
144            return capabilitiesDocument;
145        }
146    
147        /**
148         * This method exports a 1.3.0 capabilities document as 1.1.1, providing backward compatibility.
149         *
150         * @param capabilities
151         * @return the 1.1.1 document
152         * @throws IOException
153         */
154        public static WMSCapabilitiesDocument exportAs_1_1_1( WMSCapabilities_1_3_0 capabilities )
155                                throws IOException {
156            WMSCapabilitiesDocument doc = new WMSCapabilitiesDocument();
157    
158            try {
159                doc.createEmptyDocument();
160    
161                Element root = doc.getRootElement();
162    
163                root.setAttribute( "version", "1.1.1" );
164                root.setAttribute( "updateSequence", capabilities.getUpdateSequence() );
165    
166                appendService( root, capabilities.getServiceIdentification(), capabilities.getServiceProvider() );
167    
168                appendCapabilityRequests( root, capabilities.getOperationMetadata() );
169    
170                Element cap = (Element) XMLTools.getNode( root, "Capability", nsContext );
171                // we don't have that one in 1.3.0 data, so just make it up since it is generally
172                // enabled in deegree WMS
173                UserDefinedSymbolization uds = new UserDefinedSymbolization( true, true, false, true );
174                appendUserDefinedSymbolization( cap, uds );
175    
176                appendCapabilityLayer( cap, capabilities.getLayer() );
177    
178                Element exc = XMLTools.getRequiredElement( root, "Capability/Exception", nsContext );
179                for ( String f : capabilities.getExceptions() ) {
180                    if ( f.equalsIgnoreCase( "XML" ) ) {
181                        f = "application/vnd.ogc.se_xml";
182                    }
183                    if ( f.equalsIgnoreCase( "INIMAGE" ) ) {
184                        f = "application/vnd.ogc.se_inimage";
185                    }
186                    if ( f.equalsIgnoreCase( "BLANK" ) ) {
187                        f = "application/vnd.ogc.se_blank";
188                    }
189                    XMLTools.appendElement( exc, null, "Format", f );
190                }
191    
192            } catch ( XMLParsingException e ) {
193                LOG.logError( e.getMessage(), e );
194            } catch ( SAXException e ) {
195                LOG.logError( e.getMessage(), e );
196            }
197    
198            return doc;
199        }
200    
201        /**
202         *
203         * @param root
204         * @param uds
205         */
206        protected static void appendUserDefinedSymbolization( Element root, UserDefinedSymbolization uds ) {
207    
208            Element elem = XMLTools.appendElement( root, null, "UserDefinedSymbolization" );
209            elem.setAttribute( "SupportSLD", boolean2Number( uds.isSldSupported() ) );
210            elem.setAttribute( "UserLayer", boolean2Number( uds.isUserLayerSupported() ) );
211            elem.setAttribute( "UserStyle", boolean2Number( uds.isUserStyleSupported() ) );
212            elem.setAttribute( "RemoteWFS", boolean2Number( uds.isRemoteWFSSupported() ) );
213    
214        }
215    
216        private static String boolean2Number( boolean bool ) {
217            if ( bool ) {
218                return "1";
219            }
220            return "0";
221        }
222    
223        /**
224         *
225         * @param root
226         * @param identification
227         * @param provider
228         * @throws XMLParsingException
229         */
230        protected static void appendService( Element root, ServiceIdentification identification, ServiceProvider provider )
231                                throws XMLParsingException {
232    
233            root = (Element) XMLTools.getRequiredNode( root, "./Service", nsContext );
234    
235            Element node = (Element) XMLTools.getRequiredNode( root, "./Name", nsContext );
236            // is this actually desired?
237            node.setTextContent( "OGC:WMS" );
238    
239            node = (Element) XMLTools.getRequiredNode( root, "./Title", nsContext );
240            node.setTextContent( identification.getTitle() );
241    
242            String serviceAbstract = identification.getAbstractString();
243            if ( serviceAbstract != null ) {
244                XMLTools.appendElement( root, null, "Abstract", serviceAbstract );
245            }
246    
247            List<Keywords> keywords = identification.getKeywords();
248            if ( keywords.size() > 0 ) {
249                String[] kw = keywords.get( 0 ).getKeywords();
250                Element kwl = XMLTools.appendElement( root, null, "KeywordList" );
251                for ( int i = 0; i < kw.length; i++ ) {
252                    XMLTools.appendElement( kwl, null, "Keyword", kw[i] );
253                }
254            }
255    
256            node = root.getOwnerDocument().createElement( "OnlineResource" );
257    
258            OnlineResource sLink = provider.getProviderSite();
259            org.deegree.model.metadata.iso19115.XMLFactory.appendOnlineResource( node, sLink );
260    
261            root.appendChild( node );
262    
263            appendContactInformation( root, provider );
264    
265            String fee = null;
266            if ( identification.getAccessConstraints().size() > 0 )
267                fee = identification.getAccessConstraints().get( 0 ).getFees();
268            if ( fee != null ) {
269                XMLTools.appendElement( root, null, "Fees", fee );
270            } else {
271                XMLTools.appendElement( root, null, "Fees", "none" );
272            }
273    
274            if ( identification.getAccessConstraints().size() > 0 ) {
275                XMLTools.appendElement( root, null, "AccessConstraints",
276                                        identification.getAccessConstraints().get( 0 ).getUseLimitations().get( 0 ) );
277            } else {
278                XMLTools.appendElement( root, null, "AccessConstraints", "none" );
279            }
280    
281        }
282    
283        /**
284         *
285         * @param root
286         * @param provider
287         */
288        protected static void appendContactInformation( Element root, ServiceProvider provider ) {
289    
290            Element ciNode = XMLTools.appendElement( root, null, "ContactInformation" );
291            Element cppNode = XMLTools.appendElement( ciNode, null, "ContactPersonPrimary" );
292            if ( provider.getServiceContact().getIndividualName().length > 0 ) {
293                XMLTools.appendElement( cppNode, null, "ContactPerson", provider.getServiceContact().getIndividualName()[0] );
294            }
295            if ( provider.getServiceContact().getOrganisationName().length > 0 ) {
296                XMLTools.appendElement( cppNode, null, "ContactOrganization",
297                                        provider.getServiceContact().getOrganisationName()[0] );
298            }
299            if ( provider.getServiceContact().getPositionName().length > 0 ) {
300                XMLTools.appendElement( ciNode, null, "ContactPosition", provider.getServiceContact().getPositionName()[0] );
301            }
302            Element caNode = XMLTools.appendElement( ciNode, null, "ContactAddress" );
303    
304            XMLTools.appendElement( caNode, null, "AddressType", "postal" );
305    
306            if ( provider.getServiceContact().getContactInfo().length > 0 ) {
307                Address addr = provider.getServiceContact().getContactInfo()[0].getAddress();
308                String[] dp = addr.getDeliveryPoint();
309                if ( dp.length > 0 ) {
310                    XMLTools.appendElement( caNode, null, "Address", dp[0] );
311                }
312                if ( addr.getCity() != null ) {
313                    XMLTools.appendElement( caNode, null, "City", addr.getCity() );
314                }
315                if ( addr.getAdministrativeArea() != null ) {
316                    XMLTools.appendElement( caNode, null, "StateOrProvince", addr.getAdministrativeArea() );
317                }
318                if ( addr.getPostalCode() != null ) {
319                    XMLTools.appendElement( caNode, null, "PostCode", addr.getPostalCode() );
320                }
321                if ( addr.getCountry() != null ) {
322                    XMLTools.appendElement( caNode, null, "Country", addr.getCountry() );
323                }
324    
325                Phone phone = provider.getServiceContact().getContactInfo()[0].getPhone();
326                if ( phone.getVoice().length > 0 ) {
327                    XMLTools.appendElement( ciNode, null, "ContactVoiceTelephone", phone.getVoice()[0] );
328                }
329                if ( phone.getFacsimile().length > 0 ) {
330                    XMLTools.appendElement( ciNode, null, "ContactFacsimileTelephone", phone.getFacsimile()[0] );
331                }
332                if ( addr.getElectronicMailAddress().length > 0 ) {
333                    XMLTools.appendElement( ciNode, null, "ContactElectronicMailAddress",
334                                            addr.getElectronicMailAddress()[0] );
335                }
336            }
337    
338        }
339    
340        /**
341         *
342         * @param root
343         * @param operationsMetadata
344         * @throws XMLParsingException
345         */
346        protected static void appendCapabilityRequests( Element root, OperationsMetadata operationsMetadata )
347                                throws XMLParsingException {
348    
349            root = (Element) XMLTools.getRequiredNode( root, "./Capability/Request", nsContext );
350    
351            operationsMetadata.getOperations();
352    
353            // just append all operations
354            for ( Operation operation : operationsMetadata.getOperations() ) {
355                appendOperation( root, operation );
356            }
357    
358        }
359    
360        /**
361         *
362         * @param root
363         * @param operation
364         */
365        protected static void appendOperation( Element root, Operation operation ) {
366    
367            String name = operation.getName().getLocalName();
368    
369            root = XMLTools.appendElement( root, null, name );
370    
371            DomainType odt = (DomainType) operation.getParameter( new QualifiedName( "Format" ) );
372    
373            List<TypedLiteral> values = odt.getValues();
374            for ( TypedLiteral value : values )
375                XMLTools.appendElement( root, null, "Format", value.getValue() );
376    
377            List<DCP> dcps = operation.getDCP();
378            for ( DCP dcp : dcps ) {
379                Element http = XMLTools.appendElement( root, null, "DCPType" );
380                http = XMLTools.appendElement( http, null, "HTTP" );
381                HTTP ht = (HTTP) dcp;
382                List<HTTP.Type> types = ht.getTypes();
383                List<OnlineResource> links = ht.getLinks();
384                for ( int i = 0; i < types.size(); ++i ) {
385                    Element elem = null;
386                    if ( types.get( i ) == HTTP.Type.Get )
387                        elem = XMLTools.appendElement( http, null, "Get" );
388                    if ( types.get( i ) == HTTP.Type.Post )
389                        elem = XMLTools.appendElement( http, null, "Post" );
390                    if ( elem != null ) {
391                        elem = XMLTools.appendElement( elem, null, "OnlineResource" );
392                        org.deegree.model.metadata.iso19115.XMLFactory.appendOnlineResource( elem, links.get( i ) );
393                    }
394                }
395            }
396    
397        }
398    
399        /**
400         *
401         * @param root
402         * @param layer
403         * @throws XMLParsingException
404         */
405        protected static void appendCapabilityLayer( Element root, Layer layer )
406                                throws XMLParsingException {
407    
408            root = XMLTools.appendElement( root, null, "Layer" );
409            root.setAttribute( "queryable", boolean2Number( layer.isQueryable() ) );
410            root.setAttribute( "cascaded", Integer.toString( layer.getCascaded() ) );
411            root.setAttribute( "opaque", boolean2Number( layer.isOpaque() ) );
412            root.setAttribute( "noSubsets", boolean2Number( layer.hasNoSubsets() ) );
413            if ( layer.getFixedWidth() > 0 ) {
414                root.setAttribute( "fixedWidth", Integer.toString( layer.getFixedWidth() ) );
415            }
416            if ( layer.getFixedHeight() > 0 ) {
417                root.setAttribute( "fixedHeight", Integer.toString( layer.getFixedHeight() ) );
418            }
419    
420            if ( layer.getName() != null ) {
421                XMLTools.appendElement( root, null, "Name", layer.getName() );
422            }
423            XMLTools.appendElement( root, null, "Title", layer.getTitle() );
424    
425            if ( layer.getAbstract() != null ) {
426                XMLTools.appendElement( root, null, "Abstract", layer.getAbstract() );
427            }
428    
429            String[] keywords = layer.getKeywordList();
430            if ( keywords.length > 0 ) {
431                Element elem = XMLTools.appendElement( root, null, "KeywordList" );
432                for ( int i = 0; i < keywords.length; i++ ) {
433                    XMLTools.appendElement( elem, null, "Keyword", keywords[i] );
434                }
435            }
436    
437            String[] srs = layer.getSrs();
438            for ( int i = 0; i < srs.length; i++ ) {
439                XMLTools.appendElement( root, null, "SRS", srs[i] );
440            }
441    
442            Envelope llBox = layer.getLatLonBoundingBox();
443            appendLatLonBoundingBox( root, llBox );
444    
445            LayerBoundingBox[] lBoxes = layer.getBoundingBoxes();
446            for ( int i = 0; i < lBoxes.length; i++ ) {
447                appendLayerBoundingBox( root, lBoxes[i] );
448            }
449    
450            Dimension[] dims = layer.getDimension();
451            for ( int i = 0; i < dims.length; i++ ) {
452                appendDimension( root, dims[i] );
453            }
454    
455            Extent[] extents = layer.getExtent();
456            for ( int i = 0; i < extents.length; i++ ) {
457                appendExtent( root, extents[i] );
458            }
459    
460            Attribution attr = layer.getAttribution();
461            if ( attr != null ) {
462                appendAttribution( root, attr );
463            }
464    
465            AuthorityURL[] authorityURLs = layer.getAuthorityURL();
466            for ( int i = 0; i < authorityURLs.length; i++ ) {
467                appendAuthorityURL( root, authorityURLs[i] );
468            }
469    
470            Identifier[] identifiers = layer.getIdentifier();
471            for ( int i = 0; i < identifiers.length; i++ ) {
472                appendIdentifier( root, identifiers[i] );
473            }
474    
475            MetadataURL[] metadataURLs = layer.getMetadataURL();
476            for ( int i = 0; i < metadataURLs.length; i++ ) {
477                appendMetadataURL( root, metadataURLs[i] );
478            }
479    
480            DataURL[] dataURLs = layer.getDataURL();
481            for ( int i = 0; i < dataURLs.length; i++ ) {
482                appendDataURL( root, dataURLs[i] );
483            }
484    
485            FeatureListURL[] featureListURLs = layer.getFeatureListURL();
486            for ( int i = 0; i < featureListURLs.length; i++ ) {
487                appendFeatureListURL( root, featureListURLs[i] );
488            }
489    
490            if ( layer.getName() != null && layer.getName().length() > 0 ) {
491                Style[] styles = layer.getStyles();
492                for ( int i = 0; i < styles.length; i++ ) {
493                    appendStyle( root, styles[i] );
494                }
495            }
496    
497            ScaleHint scaleHint = layer.getScaleHint();
498            Element elem = XMLTools.appendElement( root, null, "ScaleHint" );
499            elem.setAttribute( "min", "" + scaleHint.getMin() );
500            elem.setAttribute( "max", "" + scaleHint.getMax() );
501    
502            Layer[] layers = layer.getLayer();
503            for ( int i = 0; i < layers.length; i++ ) {
504                appendCapabilityLayer( root, layers[i] );
505            }
506    
507        }
508    
509        /**
510         *
511         * @param root
512         * @param style
513         */
514        protected static void appendStyle( Element root, Style style ) {
515    
516            String nm = style.getName();
517            String tlt = style.getTitle();
518            if ( nm.startsWith( "default:" ) ) {
519                nm = "default";
520                if ( tlt != null ) {
521                    tlt = StringTools.replace( tlt, "default:", "", false ) + " (default)";
522                }
523            }
524    
525            root = XMLTools.appendElement( root, null, "Style" );
526            XMLTools.appendElement( root, null, "Name", nm );
527            if ( style.getTitle() != null ) {
528                XMLTools.appendElement( root, null, "Title", tlt );
529            }
530            if ( style.getAbstract() != null ) {
531                XMLTools.appendElement( root, null, "Abstract", style.getAbstract() );
532            }
533            LegendURL[] legendURLs = style.getLegendURL();
534            for ( int i = 0; i < legendURLs.length; i++ ) {
535                appendLegendURL( root, legendURLs[i] );
536            }
537    
538            StyleSheetURL styleSheetURL = style.getStyleSheetURL();
539            if ( styleSheetURL != null ) {
540                appendStyleSheetURL( root, styleSheetURL );
541            }
542    
543            StyleURL styleURL = style.getStyleURL();
544            if ( styleURL != null ) {
545                appendStyleURL( root, styleURL );
546            }
547    
548        }
549    
550        /**
551         * @param root
552         * @param styleURL
553         */
554        protected static void appendStyleURL( Element root, StyleURL styleURL ) {
555            Element elem = XMLTools.appendElement( root, null, "StyleURL" );
556            XMLTools.appendElement( elem, null, "Format", styleURL.getFormat() );
557            appendOnlineResource( elem, styleURL.getOnlineResource(), false );
558        }
559    
560        /**
561         * @param root
562         * @param styleSheetURL
563         */
564        protected static void appendStyleSheetURL( Element root, StyleSheetURL styleSheetURL ) {
565            Element elem = XMLTools.appendElement( root, null, "StyleSheetURL" );
566            XMLTools.appendElement( elem, null, "Format", styleSheetURL.getFormat() );
567            appendOnlineResource( elem, styleSheetURL.getOnlineResource(), false );
568        }
569    
570        /**
571         * @param root
572         * @param legendURL
573         */
574        protected static void appendLegendURL( Element root, LegendURL legendURL ) {
575            Element elem = XMLTools.appendElement( root, null, "LegendURL" );
576            elem.setAttribute( "width", "" + legendURL.getWidth() );
577            elem.setAttribute( "height", "" + legendURL.getHeight() );
578            XMLTools.appendElement( elem, null, "Format", legendURL.getFormat() );
579    
580            appendOnlineResource( elem, legendURL.getOnlineResource(), false );
581        }
582    
583        /**
584         * @param root
585         * @param featureListURL
586         */
587        protected static void appendFeatureListURL( Element root, FeatureListURL featureListURL ) {
588            Element elem = XMLTools.appendElement( root, null, "FeatureListURL" );
589            XMLTools.appendElement( elem, null, "Format", featureListURL.getFormat() );
590            appendOnlineResource( elem, featureListURL.getOnlineResource(), false );
591        }
592    
593        /**
594         * @param root
595         * @param dataURL
596         */
597        protected static void appendDataURL( Element root, DataURL dataURL ) {
598            Element elem = XMLTools.appendElement( root, null, "DataURL" );
599            XMLTools.appendElement( elem, null, "Format", dataURL.getFormat() );
600            appendOnlineResource( elem, dataURL.getOnlineResource(), false );
601        }
602    
603        /**
604         * @param root
605         * @param metadataURL
606         */
607        protected static void appendMetadataURL( Element root, MetadataURL metadataURL ) {
608            Element elem = XMLTools.appendElement( root, null, "MetadataURL" );
609            elem.setAttribute( "type", metadataURL.getType() );
610            XMLTools.appendElement( elem, null, "Format", metadataURL.getFormat() );
611            appendOnlineResource( elem, metadataURL.getOnlineResource(), false );
612        }
613    
614        /**
615         * @param root
616         * @param identifier
617         */
618        protected static void appendIdentifier( Element root, Identifier identifier ) {
619            Element elem = XMLTools.appendElement( root, null, "Identifier" );
620            elem.setAttribute( "authority", identifier.getAuthority() );
621            elem.setTextContent( identifier.getValue() );
622        }
623    
624        /**
625         * @param root
626         * @param authorityURL
627         */
628        protected static void appendAuthorityURL( Element root, AuthorityURL authorityURL ) {
629            Element elem = XMLTools.appendElement( root, null, "AuthorityURL" );
630            elem.setAttribute( "name", authorityURL.getName() );
631            appendOnlineResource( elem, authorityURL.getOnlineResource(), false );
632        }
633    
634        /**
635         * @param root
636         * @param attr
637         */
638        protected static void appendAttribution( Element root, Attribution attr ) {
639            Element elem = XMLTools.appendElement( root, null, "Attribution" );
640            XMLTools.appendElement( elem, null, "Title", attr.getTitle() );
641            appendOnlineResource( elem, attr.getOnlineResource(), false );
642            LogoURL logoURL = attr.getLogoURL();
643            if ( logoURL != null ) {
644                elem = XMLTools.appendElement( elem, null, "LogoURL" );
645                elem.setAttribute( "width", "" + logoURL.getWidth() );
646                elem.setAttribute( "height", "" + logoURL.getHeight() );
647                XMLTools.appendElement( elem, null, "Format", logoURL.getFormat() );
648                appendOnlineResource( elem, logoURL.getOnlineResource(), false );
649            }
650        }
651    
652        /**
653         * @param root
654         * @param url
655         * @param appendFineChar
656         */
657        protected static void appendOnlineResource( Element root, URL url, boolean appendFineChar ) {
658    
659            Element olr = XMLTools.appendElement( root, null, "OnlineResource" );
660            olr.setAttributeNS( "http://www.w3.org/1999/xlink", "xlink:type", "simple" );
661            if ( appendFineChar ) {
662                // according to OGC WMS 1.1.1 & 1.3 Testsuite a URL to a service operation
663                // via HTTPGet must end with '?' or '&'
664                String href = OWSUtils.validateHTTPGetBaseURL( url.toExternalForm() );
665                olr.setAttributeNS( "http://www.w3.org/1999/xlink", "xlink:href", href );
666            } else {
667                olr.setAttributeNS( "http://www.w3.org/1999/xlink", "xlink:href", url.toExternalForm() );
668            }
669        }
670    
671        /**
672         * @param root
673         * @param extent
674         */
675        protected static void appendExtent( Element root, Extent extent ) {
676            Element exNode = XMLTools.appendElement( root, null, "Extent" );
677            exNode.setAttribute( "name", extent.getName() );
678            exNode.setAttribute( "default", extent.getDefault() );
679            exNode.setAttribute( "nearestValue", boolean2Number( extent.useNearestValue() ) );
680            exNode.setTextContent( extent.getValue() );
681        }
682    
683        /**
684         * @param root
685         * @param dim
686         */
687        protected static void appendDimension( Element root, Dimension dim ) {
688            Element dimNode = XMLTools.appendElement( root, null, "Dimension" );
689            dimNode.setAttribute( "name", dim.getName() );
690            dimNode.setAttribute( "units", dim.getUnits() );
691            dimNode.setAttribute( "unitSymbol", dim.getUnitSymbol() );
692        }
693    
694        /**
695         * @param root
696         * @param lBox
697         */
698        protected static void appendLayerBoundingBox( Element root, LayerBoundingBox lBox ) {
699            Element bbNode = XMLTools.appendElement( root, null, "BoundingBox" );
700            bbNode.setAttribute( "minx", "" + lBox.getMin().getX() );
701            bbNode.setAttribute( "miny", "" + lBox.getMin().getY() );
702            bbNode.setAttribute( "maxx", "" + lBox.getMax().getX() );
703            bbNode.setAttribute( "maxy", "" + lBox.getMax().getY() );
704            bbNode.setAttribute( "resx", "" + lBox.getResx() );
705            bbNode.setAttribute( "resy", "" + lBox.getResy() );
706            bbNode.setAttribute( "SRS", "" + lBox.getSRS() );
707        }
708    
709        /**
710         * @param root
711         * @param llBox
712         */
713        protected static void appendLatLonBoundingBox( Element root, Envelope llBox ) {
714            Element bbNode = XMLTools.appendElement( root, null, "LatLonBoundingBox" );
715            bbNode.setAttribute( "minx", "" + llBox.getMin().getX() );
716            bbNode.setAttribute( "miny", "" + llBox.getMin().getY() );
717            bbNode.setAttribute( "maxx", "" + llBox.getMax().getX() );
718            bbNode.setAttribute( "maxy", "" + llBox.getMax().getY() );
719        }
720    
721    }