001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/XMLFactory.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    
044    package org.deegree.ogcwebservices.wpvs;
045    
046    import java.io.IOException;
047    import java.net.URI;
048    import java.net.URL;
049    
050    import org.deegree.datatypes.values.TypedLiteral;
051    import org.deegree.datatypes.values.ValueRange;
052    import org.deegree.framework.xml.XMLTools;
053    import org.deegree.model.crs.CoordinateSystem;
054    import org.deegree.model.spatialschema.Envelope;
055    import org.deegree.ogcbase.BaseURL;
056    import org.deegree.ogcbase.CommonNamespaces;
057    import org.deegree.ogcbase.ImageURL;
058    import org.deegree.ogcwebservices.getcapabilities.DCPType;
059    import org.deegree.ogcwebservices.getcapabilities.OperationsMetadata;
060    import org.deegree.ogcwebservices.getcapabilities.ServiceIdentification;
061    import org.deegree.ogcwebservices.getcapabilities.ServiceProvider;
062    import org.deegree.ogcwebservices.wpvs.capabilities.DataProvider;
063    import org.deegree.ogcwebservices.wpvs.capabilities.Dataset;
064    import org.deegree.ogcwebservices.wpvs.capabilities.Dimension;
065    import org.deegree.ogcwebservices.wpvs.capabilities.Identifier;
066    import org.deegree.ogcwebservices.wpvs.capabilities.MetaData;
067    import org.deegree.ogcwebservices.wpvs.capabilities.Style;
068    import org.deegree.ogcwebservices.wpvs.capabilities.WPVSCapabilities;
069    import org.deegree.ogcwebservices.wpvs.capabilities.WPVSCapabilitiesDocument;
070    import org.deegree.ogcwebservices.wpvs.capabilities.WPVSOperationsMetadata;
071    import org.deegree.owscommon.OWSMetadata;
072    import org.deegree.owscommon.com110.HTTP110;
073    import org.deegree.owscommon.com110.OWSAllowedValues;
074    import org.deegree.owscommon.com110.OWSDomainType110;
075    import org.deegree.owscommon.com110.OWSRequestMethod;
076    import org.deegree.owscommon.com110.Operation110;
077    import org.w3c.dom.Element;
078    import org.w3c.dom.Text;
079    import org.xml.sax.SAXException;
080    
081    /**
082     * TODO class description
083     * 
084     * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
085     * @author last edited by: $Author: apoth $
086     * 
087     * $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
088     */
089    public class XMLFactory extends org.deegree.owscommon.XMLFactory {
090    
091        private static final URI WPVSNS = CommonNamespaces.WPVSNS;
092    
093        private static final String PRE_OWS = CommonNamespaces.OWS_PREFIX + ':';
094    
095        private static final String PRE_WPVS = CommonNamespaces.WPVS_PREFIX + ':';
096    
097        private XMLFactory() {
098            // not instantiable.
099        }
100    
101        /**
102         * This method exporst a wpvs capabilitiesDocument with following information taken from the
103         * given WPVSCapabilities
104         * <ul>
105         * <li>ServiceIdentification</li>
106         * <li>ServiceProvide</li>
107         * <li>operationMetadata</li>
108         * <li>the root dataset</li>
109         * </ul>
110         * 
111         * @param wpvsCapabilities
112         * @return the WPVSCapabilitiesDocument of this wpvs
113         * @throws IOException
114         *             if wpvsCapabilitiesDocument cannot be instantiated
115         */
116        public static WPVSCapabilitiesDocument export( WPVSCapabilities wpvsCapabilities )
117                                throws IOException {
118            XMLFactory factory = new XMLFactory();
119            return factory.createCapabilitiesDocument( wpvsCapabilities );
120        }
121    
122        private WPVSCapabilitiesDocument createCapabilitiesDocument( WPVSCapabilities wpvsCapabilities )
123                                throws IOException {
124            WPVSCapabilitiesDocument wpvsCapabilitiesDocument = new WPVSCapabilitiesDocument();
125            try {
126                wpvsCapabilitiesDocument.createEmptyDocument();
127                Element root = wpvsCapabilitiesDocument.getRootElement();
128    
129                ServiceIdentification serviceIdentification = wpvsCapabilities.getServiceIdentification();
130                if ( serviceIdentification != null ) {
131                    appendServiceIdentification( root, serviceIdentification );
132                }
133    
134                ServiceProvider serviceProvider = wpvsCapabilities.getServiceProvider();
135                if ( serviceProvider != null ) {
136                    appendServiceProvider( root, serviceProvider );
137                }
138    
139                OperationsMetadata operationMetadata = wpvsCapabilities.getOperationsMetadata();
140                if ( operationMetadata != null && operationMetadata instanceof WPVSOperationsMetadata ) {
141                    appendWPVSOperationsMetadata( root, (WPVSOperationsMetadata) operationMetadata );
142                }
143    
144                Dataset dataset = wpvsCapabilities.getDataset();
145                if ( dataset != null ) {
146                    appendDataset( root, dataset );
147                }
148    
149            } catch ( SAXException e ) {
150                e.printStackTrace();
151                LOG.logError( e.getMessage(), e );
152            }
153    
154            return wpvsCapabilitiesDocument;
155        }
156    
157        /**
158         * Appends the DOM representation of an <code>WPVSOperationsMetadata</code> to the passed
159         * <code>Element</code>.
160         * 
161         * @param root
162         * @param operationsMetadata
163         */
164        private void appendWPVSOperationsMetadata( Element root, WPVSOperationsMetadata operationsMetadata ) {
165            // 'ows:OperationsMetadata'-element
166            Element operationsMetadataNode = XMLTools.appendElement( root, OWSNS, PRE_OWS + "OperationsMetadata" );
167    
168            // append all Operations
169            Operation110[] operations = (Operation110[]) operationsMetadata.getAllOperations();
170            for ( int i = 0; i < operations.length; i++ ) {
171                Operation110 operation = operations[i];
172    
173                // 'ows:Operation' - element
174                Element operationElement = XMLTools.appendElement( operationsMetadataNode, OWSNS, PRE_OWS + "Operation" );
175                operationElement.setAttribute( "name", operation.getName() );
176    
177                // 'ows:DCP' - elements
178                DCPType[] dcps = operation.getDCPs();
179                for ( int j = 0; j < dcps.length; j++ ) {
180                    appendDCPValue( operationElement, dcps[j] );
181                }
182    
183                // 'ows:Parameter' - elements
184                OWSDomainType110[] parameters = operation.getParameters110();
185                for ( int j = 0; j < parameters.length; j++ ) {
186                    appendDomainType( operationElement, parameters[j], PRE_OWS + "Parameter" );
187                }
188    
189                // 'ows:Constraint' - elements
190                OWSDomainType110[] constraints = operation.getConstraints110();
191                for ( int j = 0; j < constraints.length; j++ ) {
192                    appendDomainType( operationElement, constraints[j], PRE_OWS + "Constraint" );
193                }
194    
195                // 'ows:Metadata' - elements
196                OWSMetadata[] metadata = operation.getMetadata110();
197                for ( int j = 0; j < metadata.length; j++ ) {
198                    appendOWSMetadata( operationElement, metadata[j], PRE_OWS + "Metadata" );
199                }
200            }
201    
202            // append general parameters
203            OWSDomainType110[] parameters = operationsMetadata.getParameters110();
204            for ( int i = 0; i < parameters.length; i++ ) {
205                appendDomainType( operationsMetadataNode, parameters[i], PRE_OWS + "Parameter" );
206            }
207    
208            // append general constraints
209            OWSDomainType110[] constraints = operationsMetadata.getConstraints110();
210            for ( int i = 0; i < constraints.length; i++ ) {
211                appendDomainType( operationsMetadataNode, constraints[i], PRE_OWS + "Constraint" );
212            }
213    
214            // append 'ows:ExtendedCapabilities'
215            // TODO when needed.
216    
217        }
218    
219        /**
220         * Appends the DOM representation of an <code>OWSMetadata</code> to the passed
221         * <code>Element</code>. The given <code>String</code> is used to distinguish between the
222         * different Metadata types.
223         * 
224         * @param element
225         * @param metadata
226         * @param tagName
227         */
228        private void appendOWSMetadata( Element element, OWSMetadata metadata, String tagName ) {
229    
230            if ( metadata != null ) {
231    
232                Element metadataElement = XMLTools.appendElement( element, OWSNS, tagName );
233    
234                appendSimpleLinkAttributes( metadataElement, metadata.getLink() );
235    
236                Element nameElement = XMLTools.appendElement( metadataElement, OWSNS, CommonNamespaces.OWS_PREFIX + ":Name" );
237                metadataElement.appendChild( nameElement );
238                nameElement.setNodeValue( metadata.getName() );
239            }
240    
241        }
242    
243        /**
244         * Appends the DOM representation of an <code>OWSDomainType</code> to the passed
245         * <code>Element</code>. The given <code>String</code> is used to distinguish between
246         * <code>Parameter</code> and <code>Constraint</code>.
247         * 
248         * @param element
249         * @param domainType
250         * @param tagName
251         */
252        private void appendDomainType( Element element, OWSDomainType110 domainType, String tagName ) {
253    
254            Element domainElement = XMLTools.appendElement( element, OWSNS, tagName );
255    
256            // attribute
257            domainElement.setAttribute( "name", domainType.getName() );
258    
259            // elements
260            OWSAllowedValues allowedValues = domainType.getAllowedValues();
261            OWSMetadata valuesListReference = domainType.getValuesListReference();
262            if ( allowedValues != null ) {
263                appendAllowedValues( domainElement, allowedValues );
264            }
265            // else if ( domainType.isAnyValue() ) {
266            // Element anyElement = XMLTools.appendElement( domainElement, OWSNS,
267            // CommonNamespaces.OWS_PREFIX+":AnyValue" );
268            // // TODO content of this tag!
269            // } else if ( domainType.hasNoValues() ) {
270            // Element noValuesElement = XMLTools.appendElement( domainElement, OWSNS,
271            // CommonNamespaces.OWS_PREFIX+":NoValues" );
272            // // TODO content of this tag!
273            // }
274            else if ( valuesListReference != null ) {
275                appendOWSMetadata( domainElement, valuesListReference, CommonNamespaces.OWS_PREFIX + ":ValuesListReference" );
276            } else {
277                // TODO "domainType object is invalid!"
278            }
279    
280            appendTypedLiteral( domainElement, domainType.getDefaultValue(), PRE_OWS + "DefaultValue", OWSNS );
281    
282            appendOWSMetadata( domainElement, domainType.getMeaning(), PRE_OWS + "Meaning" );
283    
284            appendOWSMetadata( domainElement, domainType.getOwsDataType(), PRE_OWS + "DataType" );
285    
286            String measurement = domainType.getMeasurementType();
287            if ( OWSDomainType110.REFERENCE_SYSTEM.equals( measurement ) ) {
288                appendOWSMetadata( domainElement, domainType.getMeasurement(), PRE_OWS + "ReferenceSystem" );
289            } else if ( OWSDomainType110.UOM.equals( measurement ) ) {
290                appendOWSMetadata( domainElement, domainType.getMeasurement(), PRE_OWS + "UOM" );
291            }
292    
293            OWSMetadata[] metadata = domainType.getMetadata();
294            for ( int i = 0; i < metadata.length; i++ ) {
295                appendOWSMetadata( domainElement, metadata[i], PRE_OWS + "Metadata" );
296            }
297    
298        }
299    
300        /**
301         * Appends the DOM representation of an <code>OWSAllowedValues</code> object to the passed
302         * <code>Element</code>.
303         * 
304         * @param element
305         * @param allowedValues
306         */
307        private void appendAllowedValues( Element element, OWSAllowedValues allowedValues ) {
308    
309            Element allowedElement = XMLTools.appendElement( element, OWSNS, PRE_OWS + "AllowedValues" );
310    
311            TypedLiteral[] literals = allowedValues.getOwsValues();
312            for ( int i = 0; i < literals.length; i++ ) {
313                appendTypedLiteral( allowedElement, literals[i], PRE_OWS + "Value", OWSNS );
314            }
315    
316            ValueRange[] range = allowedValues.getValueRanges();
317            for ( int i = 0; i < range.length; i++ ) {
318                Element rangeElement = XMLTools.appendElement( allowedElement, OWSNS, PRE_OWS + "Range" );
319    
320                appendTypedLiteral( rangeElement, range[i].getMin(), PRE_OWS + "MinimumValue", OWSNS );
321                appendTypedLiteral( rangeElement, range[i].getMax(), PRE_OWS + "MaximumValue", OWSNS );
322                appendTypedLiteral( rangeElement, range[i].getSpacing(), PRE_OWS + "Spacing", OWSNS );
323            }
324    
325        }
326    
327        /*
328         * (non-Javadoc)
329         * 
330         * @see org.deegree.owscommon.XMLFactory#appendDCP(org.w3c.dom.Element,
331         *      org.deegree.ogcwebservices.getcapabilities.DCPType)
332         */
333        private void appendDCPValue( Element operationElement, DCPType dcp ) {
334    
335            // 'ows:DCP'-element
336            Element dcpNode = XMLTools.appendElement( operationElement, OWSNS, PRE_OWS + "DCP" );
337    
338            // currently, the only supported DCP are HTTP and HTTP110!
339            if ( dcp.getProtocol() instanceof HTTP110 ) {
340                HTTP110 http = (HTTP110) dcp.getProtocol();
341    
342                // 'ows:HTTP'-element
343                Element httpNode = XMLTools.appendElement( dcpNode, OWSNS, PRE_OWS + "HTTP" );
344    
345                // 'ows:Get'-elements
346                OWSRequestMethod[] getRequest = http.getGetRequests();
347                for ( int i = 0; i < getRequest.length; i++ ) {
348                    appendRequest( httpNode, PRE_OWS + "Get", getRequest[i] );
349                }
350    
351                // 'ows:Post'-elements
352                OWSRequestMethod[] postRequest = http.getPostRequests();
353                for ( int i = 0; i < postRequest.length; i++ ) {
354                    appendRequest( httpNode, PRE_OWS + "Post", postRequest[i] );
355                }
356            }
357    
358        }
359    
360        /**
361         * Appends the DOM representation of an <code>OWSRequestMethod</code> to the passed
362         * <code>Element</code>. The given <code>String</code> is used to distinguish between
363         * <code>ows:Get</code> and <code>ows:Post</code> requests.
364         * 
365         * @param httpNode
366         * @param type
367         * @param request
368         */
369        private void appendRequest( Element httpNode, String type, OWSRequestMethod request ) {
370    
371            Element owsElement = XMLTools.appendElement( httpNode, OWSNS, type );
372    
373            appendSimpleLinkAttributes( owsElement, request.getLink() );
374    
375            OWSDomainType110[] constraint = request.getConstraints();
376            for ( int i = 0; i < constraint.length; i++ ) {
377                appendDomainType( owsElement, constraint[i], PRE_OWS + "Constraint" );
378            }
379    
380        }
381    
382        /**
383         * Appends the DOM representation of a <code>Dataset</code> to the passed <code>Element</code>.
384         * 
385         * @param root
386         * @param dataset
387         */
388        private void appendDataset( Element root, Dataset dataset ) {
389    
390            // 'wpvs:Dataset'-element (parent)
391            Element datasetNode = XMLTools.appendElement( root, WPVSNS, PRE_WPVS + "Dataset" );
392    
393            // attributes
394            datasetNode.setAttribute( "queryable", ( ( dataset.getQueryable() ) ? "1" : "0" ) );
395            datasetNode.setAttribute( "opaque", ( ( dataset.getOpaque() ) ? "1" : "0" ) );
396            datasetNode.setAttribute( "noSubsets", ( ( dataset.getNoSubset() ) ? "1" : "0" ) );
397            datasetNode.setAttribute( "fixedWidth", String.valueOf( dataset.getFixedWidth() ) );
398            datasetNode.setAttribute( "fixedHeight", String.valueOf( dataset.getFixedHeight() ) );
399    
400            // optional 'wpvs:Name'-element
401            appendName( datasetNode, dataset );
402    
403            // mandatory 'wpvs:Title'-element
404            appendTitle( datasetNode, dataset );
405    
406            // optional 'wpvs:Abstract'-element
407            appendAbstract( datasetNode, dataset );
408    
409            // optional 'ows:Keywords'-elements
410            appendOWSKeywords( datasetNode, dataset.getKeywords() );
411    
412            // optional 'wpvs:CRS'-elements
413            appendCRSNodes( datasetNode, dataset.getCrs() );
414    
415            // optional 'wpvs:Format'-elements
416            appendFormats( datasetNode, dataset.getMimeTypeFormat() );
417    
418            // mandatory 'ows:WGS84BoundingBox
419            appendBoundingBox( datasetNode, dataset.getWgs84BoundingBox(), PRE_OWS + "WGS84BoundingBox",
420                               "urn:ogc:def:crs:OGC:2:84", "2" );
421    
422            // optional 'ows:BoundingBox'-elements
423            Envelope[] boundingBoxes = dataset.getBoundingBoxes();
424    
425            for ( int i = 0; i < boundingBoxes.length; i++ ) {
426    
427                if ( boundingBoxes[i] != null ) {
428                    String crsName = boundingBoxes[i].getCoordinateSystem().getName();
429    
430                    appendBoundingBox( datasetNode, boundingBoxes[i], PRE_OWS + "BoundingBox", crsName, "2" );
431                }
432            }
433    
434            // optional 'wpvs:Dimension'-elements
435            appendDimensions( datasetNode, dataset.getDimensions() );
436    
437            // optional 'wpvs:DataProvider'-element
438            appendDataProvider( datasetNode, dataset.getDataProvider() );
439    
440            // mandatory 'wpvs:Identifier'-element
441            appendIdentifier( datasetNode, dataset.getIdentifier() );
442    
443            // 'wpvs:MetaData'-elements
444            appendURLs( datasetNode, dataset.getMetadata(), WPVSNS, PRE_WPVS + "MetaData" );
445    
446            // 'wpvs:DatasetReference'-elements
447            appendURLs( datasetNode, dataset.getDatasetReferences(), WPVSNS, PRE_WPVS + "DatasetReference" );
448    
449            // 'wpvs:FeatureListReference'-elements
450            appendURLs( datasetNode, dataset.getFeatureListReferences(), WPVSNS, PRE_WPVS + "FeatureListReference" );
451    
452            // 'wpvs:Style'-elements
453            appendStyles( datasetNode, dataset.getStyles() );
454    
455            // 'wpvs:MinimumScaleDenominator'-element
456            appendScaleDenominator( datasetNode, dataset.getMinimumScaleDenominator(), "MIN" );
457    
458            // 'wpvs:MaximumScaleDenominator'-element
459            appendScaleDenominator( datasetNode, dataset.getMaximumScaleDenominator(), "MAX" );
460    
461            // 'wpvs:Dataset'-elements (children)
462            Dataset[] datasets = dataset.getDatasets();
463            for ( int i = 0; i < datasets.length; i++ ) {
464                appendDataset( datasetNode, datasets[i] );
465            }
466    
467            // 'ElevationModel'-element (the simple ogc-ElevationModel)
468            String emName = dataset.getElevationModel().getName();
469            if ( emName != null ) {
470                appendElevationModel( datasetNode, emName );
471            }
472        }
473    
474        /**
475         * Appends the DOM representation of an OGC <code>ElevationModel</code> to the passed
476         * <code>Element</code>.
477         * 
478         * @param datasetNode
479         * @param elevationModelName
480         */
481        private void appendElevationModel( Element datasetNode, String elevationModelName ) {
482    
483            Element elevation = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "ElevationModel" );
484            Text elevationText = elevation.getOwnerDocument().createTextNode( elevationModelName );
485            elevation.appendChild( elevationText );
486    
487            elevation.appendChild( elevationText );
488    
489        }
490    
491        /**
492         * Appends the DOM representations of the given <code>ScaleDenominator</code> to the passed
493         * <code>Element</code>. The given <code>String</code> is used to distinguish between
494         * MinimumsScaleDenominator and MaximumScaleDenominator.
495         * 
496         * @param datasetNode
497         * @param scaleDenominator
498         * @param extremum
499         *            must be either 'MIN' or 'MAX'.
500         */
501        private void appendScaleDenominator( Element datasetNode, double scaleDenominator, String extremum ) {
502            Element scaleElement = null;
503    
504            if ( "MIN".equalsIgnoreCase( extremum ) ) {
505                scaleElement = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "MinimumScaleDenominator" );
506            } else if ( "MAX".equalsIgnoreCase( extremum ) ) {
507                scaleElement = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "MaximumScaleDenominator" );
508            } else {
509                throw new IllegalArgumentException( "The extremum must be either 'MIN' or 'MAX'." );
510            }
511    
512            String value = String.valueOf( scaleDenominator );
513            Text scaleText = scaleElement.getOwnerDocument().createTextNode( value );
514            scaleElement.appendChild( scaleText );
515    
516        }
517    
518        /**
519         * Appends the DOM representations of the <code>Abstract</code> Element from the given
520         * <code>Object</code> to the passed <code>Element</code>.
521         * 
522         * @param root
523         * @param obj
524         *            may be of the following types: Style, Dataset.
525         */
526        private void appendAbstract( Element root, Object obj ) {
527    
528            String abstractString = null;
529            if ( obj instanceof Style ) {
530                abstractString = ( (Style) obj ).getAbstract();
531            } else if ( obj instanceof Dataset ) {
532                abstractString = ( (Dataset) obj ).getAbstract();
533            }
534            if ( abstractString != null ) {
535                Element abstractElement = XMLTools.appendElement( root, WPVSNS, PRE_WPVS + "Abstract" );
536                Text abstractText = abstractElement.getOwnerDocument().createTextNode( abstractString );
537                abstractElement.appendChild( abstractText );
538            }
539    
540        }
541    
542        /**
543         * Appends the DOM representations of the <code>Title</code> Element from the given
544         * <code>Object</code> to the passed <code>Element</code>.
545         * 
546         * @param root
547         * @param obj
548         *            may be of the following types: Style, Dataset.
549         */
550        private void appendTitle( Element root, Object obj ) {
551    
552            String title = null;
553            if ( obj instanceof Style ) {
554                title = ( (Style) obj ).getTitle();
555            } else if ( obj instanceof Dataset ) {
556                title = ( (Dataset) obj ).getTitle();
557            }
558            Element titleElement = XMLTools.appendElement( root, WPVSNS, PRE_WPVS + "Title" );
559            Text titleText = titleElement.getOwnerDocument().createTextNode( title );
560            titleElement.appendChild( titleText );
561        }
562    
563        /**
564         * Appends the DOM representations of the <code>Name</code> Element from the given
565         * <code>Object</code> to the passed <code>Element</code>.
566         * 
567         * @param root
568         * @param obj
569         *            may be of the following types: Style, Dataset.
570         */
571        private void appendName( Element root, Object obj ) {
572    
573            String name = null;
574            if ( obj instanceof Style ) {
575                name = ( (Style) obj ).getName();
576            } else if ( obj instanceof Dataset ) {
577                name = ( (Dataset) obj ).getName();
578            }
579    
580            if ( name != null ) {
581                Element nameElement = XMLTools.appendElement( root, WPVSNS, PRE_WPVS + "Name" );
582                Text nameText = nameElement.getOwnerDocument().createTextNode( name );
583                nameElement.appendChild( nameText );
584            }
585    
586        }
587    
588        /**
589         * Appends the DOM representations of the given array of <code>Style</code> to the passed
590         * <code>Element</code>.
591         * 
592         * @param datasetNode
593         * @param styles
594         */
595        private void appendStyles( Element datasetNode, Style[] styles ) {
596    
597            if ( styles != null ) {
598                for ( int i = 0; i < styles.length; i++ ) {
599    
600                    Element styleElement = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "Style" );
601    
602                    appendName( styleElement, styles[i] );
603                    appendTitle( styleElement, styles[i] );
604                    appendAbstract( styleElement, styles[i] );
605    
606                    appendOWSKeywords( styleElement, styles[i].getKeywords() );
607    
608                    if ( styles[i].getIdentifier() != null ) {
609                        appendIdentifier( styleElement, styles[i].getIdentifier() );
610                    }
611    
612                    appendURLs( styleElement, styles[i].getLegendURLs(), WPVSNS, PRE_WPVS + "LegendURL" );
613    
614                    Element styleSheetURLElement = XMLTools.appendElement( styleElement, WPVSNS, PRE_WPVS + "StyleSheetURL" );
615                    appendURL( styleSheetURLElement, styles[i].getStyleSheetURL(), WPVSNS );
616    
617                    Element styleURLElement = XMLTools.appendElement( styleElement, WPVSNS, PRE_WPVS + "StyleURL" );
618                    appendURL( styleURLElement, styles[i].getStyleURL(), WPVSNS );
619    
620                }
621            }
622        }
623    
624        /**
625         * Appends the DOM representations of the given array of <code>BaseURL</code> under the given
626         * name to the passed <code>Element</code>.
627         * 
628         * @param root
629         * @param baseURL
630         * @param uri
631         * @param newNode
632         */
633        private void appendURLs( Element root, BaseURL[] baseURL, URI uri, String newNode ) {
634            if ( baseURL != null ) {
635                for ( int i = 0; i < baseURL.length; i++ ) {
636                    Element urlElement = XMLTools.appendElement( root, uri, newNode );
637                    appendURL( urlElement, baseURL[i], uri );
638                }
639            }
640        }
641    
642        /**
643         * Appends the contents of the given <code>BaseURL</code> within the given <code>URI</code>
644         * as DOM representation to the passed URL <code>Element</code>.
645         * 
646         * @param urlElement
647         *            example: logoURLElement
648         * @param baseURL
649         *            example: dataProvider.getLogoURL()
650         * @param uri
651         *            example: "WPVSNS"
652         */
653        private void appendURL( Element urlElement, BaseURL baseURL, URI uri ) {
654    
655            // child elements of urlElement
656            Element formatElement = XMLTools.appendElement( urlElement, uri, PRE_WPVS + "Format" );
657            String format = baseURL != null ? baseURL.getFormat() : "";
658            Text formatText = formatElement.getOwnerDocument().createTextNode( format );
659            formatElement.appendChild( formatText );
660    
661            Element onlineElement = XMLTools.appendElement( urlElement, uri, PRE_WPVS + "OnlineResource" );
662            String url = ( baseURL != null && baseURL.getOnlineResource() != null ) ? baseURL.getOnlineResource().toString()
663                                                                                   : "";
664            onlineElement.setAttribute( "xlink:href", url );
665    
666            // attributes of urlElement
667            if ( baseURL instanceof ImageURL ) {
668                String width = String.valueOf( ( (ImageURL) baseURL ).getWidth() );
669                String height = String.valueOf( ( (ImageURL) baseURL ).getHeight() );
670                urlElement.setAttribute( "width", width );
671                urlElement.setAttribute( "height", height );
672    
673            } else if ( baseURL instanceof MetaData ) {
674    
675                urlElement.setAttribute( "type", ( (MetaData) baseURL ).getType() );
676            }
677    
678        }
679    
680        /**
681         * Appends the DOM representation of the given <code>Identifier</code> to the passed
682         * <code>Element</code>.
683         * 
684         * @param root
685         * @param identifier
686         */
687        private void appendIdentifier( Element root, Identifier identifier ) {
688    
689            Element idElement = XMLTools.appendElement( root, WPVSNS, PRE_WPVS + "Identifier" );
690    
691            if ( identifier.getCodeSpace() != null ) {
692                idElement.setAttribute( "codeSpace", identifier.getCodeSpace().toASCIIString() );
693            }
694    
695            Text idText = idElement.getOwnerDocument().createTextNode( identifier.getValue() );
696            idElement.appendChild( idText );
697    
698        }
699    
700        /**
701         * Appends the DOM representation of the given <code>DataProvider</code> to the passed
702         * <code>Element</code>.
703         * 
704         * @param datasetNode
705         * @param dataProvider
706         */
707        private void appendDataProvider( Element datasetNode, DataProvider dataProvider ) {
708            if ( dataProvider != null ) {
709                Element provider = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "DataProvider" );
710    
711                String provName = dataProvider.getProviderName();
712                if ( provName != null ) {
713                    Element providerName = XMLTools.appendElement( provider, WPVSNS, PRE_WPVS + "ProviderName" );
714                    Text providerNameText = providerName.getOwnerDocument().createTextNode( provName );
715                    providerName.appendChild( providerNameText );
716    
717                }
718    
719                Element providerSite = XMLTools.appendElement( provider, WPVSNS, PRE_WPVS + "ProviderSite" );
720                URL siteURL = dataProvider.getProviderSite();
721                String site = "";
722                if ( siteURL != null ) {
723                    site = siteURL.toString();
724                }
725                providerSite.setAttribute( "xlink:href", site );
726    
727                Element logoURLElement = XMLTools.appendElement( provider, WPVSNS, PRE_WPVS + "LogoURL" );
728                if ( dataProvider != null ) {
729                    appendURL( logoURLElement, dataProvider.getLogoURL(), WPVSNS );
730                }
731            }
732        }
733    
734        /**
735         * Appends the DOM representations of the given array of <code>Dimension</code> to the passed
736         * <code>Element</code>.
737         * 
738         * @param datasetNode
739         * @param dimensions
740         */
741        private void appendDimensions( Element datasetNode, Dimension[] dimensions ) {
742            if ( dimensions != null ) {
743                for ( Dimension dimension : dimensions ) {
744                    if ( dimension != null ) {
745                        Element dimensionElement = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "Dimension" );
746                        dimensionElement.setAttribute( "name", dimension.getName() );
747                        dimensionElement.setAttribute( "units", dimension.getUnits() );
748                        dimensionElement.setAttribute( "unitSymbol", dimension.getUnitSymbol() );
749                        dimensionElement.setAttribute( "default", dimension.getDefault() );
750                        dimensionElement.setAttribute( "multipleValues",
751                                                       ( ( dimension.getMultipleValues().booleanValue() ) ? "1" : "0" ) );
752                        dimensionElement.setAttribute( "nearestValue",
753                                                       ( ( dimension.getNearestValue().booleanValue() ) ? "1" : "0" ) );
754                        dimensionElement.setAttribute( "current", ( ( dimension.getCurrent().booleanValue() ) ? "1" : "0" ) );
755    
756                        Text dimensionText = dimensionElement.getOwnerDocument().createTextNode( dimension.getValue() );
757                        dimensionElement.appendChild( dimensionText );
758                    }
759                }
760            }
761        }
762    
763        /**
764         * Appends the DOM representations of the given array of <code>Format</code> to the passed
765         * <code>Element</code>.
766         * 
767         * @param datasetNode
768         * @param mimeTypeFormat
769         */
770        private void appendFormats( Element datasetNode, String[] mimeTypeFormat ) {
771    
772            if ( mimeTypeFormat != null ) {
773    
774                for ( int i = 0; i < mimeTypeFormat.length; i++ ) {
775                    Element format = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "Format" );
776                    Text formatText = format.getOwnerDocument().createTextNode( mimeTypeFormat[i] );
777                    format.appendChild( formatText );
778                }
779            }
780        }
781    
782        /**
783         * Appends the DOM representations of the given array of <code>CRS</code> to the passed
784         * <code>Element</code>.
785         * 
786         * @param datasetNode
787         * @param crs
788         */
789        private void appendCRSNodes( Element datasetNode, CoordinateSystem[] coordinateSystems ) {
790    
791            if ( coordinateSystems != null ) {
792                for ( CoordinateSystem crs : coordinateSystems ) {
793                    Element crsElement = XMLTools.appendElement( datasetNode, WPVSNS, PRE_WPVS + "CRS" );
794                    Text crsText = crsElement.getOwnerDocument().createTextNode( crs.getFormattedString() );
795                    crsElement.appendChild( crsText );
796                }
797            }
798        }
799    
800        /**
801         * Appends the DOM representation of the given parameters <code>Envelope, elementName, crsName, 
802         * dimension</code>
803         * to the passed <code>Element</code>.
804         * 
805         * elementName should be of the kind ows:WGS84BoundingBox" or "ows:BoundingBox". crsName should
806         * be of the kind "urn:ogc:def:crs:OGC:2:84" or "...TODO...". dimension should be "2".
807         * 
808         * @param root
809         * @param envelope
810         * @param elementName
811         * @param crsName
812         * @param dimension
813         */
814        private void appendBoundingBox( Element root, Envelope envelope, String elementName, String crsName,
815                                        String dimension ) {
816    
817            Element boundingBoxElement = XMLTools.appendElement( root, OWSNS, elementName );
818            boundingBoxElement.setAttribute( "crs", crsName );
819            boundingBoxElement.setAttribute( "dimensions", dimension );
820    
821            Element lowerCornerElement = XMLTools.appendElement( boundingBoxElement, OWSNS, PRE_OWS + "LowerCorner" );
822            Text lowerCornerText = lowerCornerElement.getOwnerDocument().createTextNode(
823                                                                                         envelope.getMin().getX()
824                                                                                                                 + " "
825                                                                                                                 + envelope.getMin().getY() );
826            lowerCornerElement.appendChild( lowerCornerText );
827    
828            Element upperCornerElement = XMLTools.appendElement( boundingBoxElement, OWSNS, PRE_OWS + "UpperCorner" );
829            Text upperCornerText = upperCornerElement.getOwnerDocument().createTextNode(
830                                                                                         envelope.getMax().getX()
831                                                                                                                 + " "
832                                                                                                                 + envelope.getMax().getY() );
833            upperCornerElement.appendChild( upperCornerText );
834    
835        }
836    
837    }