001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/sos/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     lat/lon GmbH
036     Aennchenstraße 19
037     53177 Bonn
038     Germany
039     E-Mail: greve@giub.uni-bonn.de
040    
041     ---------------------------------------------------------------------------*/
042    package org.deegree.ogcwebservices.sos;
043    
044    import java.net.URI;
045    import java.util.ArrayList;
046    
047    import org.deegree.framework.log.ILogger;
048    import org.deegree.framework.log.LoggerFactory;
049    import org.deegree.framework.xml.XMLFragment;
050    import org.deegree.framework.xml.XMLTools;
051    import org.deegree.model.metadata.iso19115.Address;
052    import org.deegree.model.metadata.iso19115.CitedResponsibleParty;
053    import org.deegree.model.metadata.iso19115.ContactInfo;
054    import org.deegree.model.metadata.iso19115.OnlineResource;
055    import org.deegree.model.metadata.iso19115.Phone;
056    import org.deegree.model.metadata.iso19115.RoleCode;
057    import org.deegree.ogcbase.CommonNamespaces;
058    import org.deegree.ogcwebservices.OGCWebServiceException;
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.sos.capabilities.CapabilitiesDocument;
063    import org.deegree.ogcwebservices.sos.capabilities.Platform;
064    import org.deegree.ogcwebservices.sos.capabilities.SOSCapabilities;
065    import org.deegree.ogcwebservices.sos.capabilities.Sensor;
066    import org.deegree.ogcwebservices.sos.describeplatform.DescribePlatformResult;
067    import org.deegree.ogcwebservices.sos.describeplatform.PlatformDescriptionDocument;
068    import org.deegree.ogcwebservices.sos.describeplatform.PlatformMetadata;
069    import org.deegree.ogcwebservices.sos.describesensor.DescribeSensorResult;
070    import org.deegree.ogcwebservices.sos.describesensor.SensorDescriptionDocument;
071    import org.deegree.ogcwebservices.sos.describesensor.SensorMetadata;
072    import org.deegree.ogcwebservices.sos.getobservation.GetObservationDocument;
073    import org.deegree.ogcwebservices.sos.getobservation.GetObservationResult;
074    import org.deegree.ogcwebservices.sos.om.Observation;
075    import org.deegree.ogcwebservices.sos.om.ObservationArray;
076    import org.deegree.ogcwebservices.sos.sensorml.BasicResponse;
077    import org.deegree.ogcwebservices.sos.sensorml.Classifier;
078    import org.deegree.ogcwebservices.sos.sensorml.CoordinateReferenceSystem;
079    import org.deegree.ogcwebservices.sos.sensorml.Discussion;
080    import org.deegree.ogcwebservices.sos.sensorml.EngineeringCRS;
081    import org.deegree.ogcwebservices.sos.sensorml.GeoLocation;
082    import org.deegree.ogcwebservices.sos.sensorml.GeoPositionModel;
083    import org.deegree.ogcwebservices.sos.sensorml.GeographicCRS;
084    import org.deegree.ogcwebservices.sos.sensorml.Identifier;
085    import org.deegree.ogcwebservices.sos.sensorml.LocationModel;
086    import org.deegree.ogcwebservices.sos.sensorml.Product;
087    import org.deegree.ogcwebservices.sos.sensorml.ProjectedCRS;
088    import org.deegree.ogcwebservices.sos.sensorml.Quantity;
089    import org.deegree.ogcwebservices.sos.sensorml.Reference;
090    import org.deegree.ogcwebservices.sos.sensorml.ResponseModel;
091    import org.w3c.dom.Document;
092    import org.w3c.dom.Element;
093    
094    /**
095     * export data to XML Files
096     * 
097     * @author <a href="mailto:mkulbe@lat-lon.de">Matthias Kulbe </a>
098     * @author last edited by: $Author: apoth $
099     * 
100     * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
101     */
102    public class XMLFactory extends org.deegree.owscommon.XMLFactory {
103    
104        private static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class );
105    
106        protected static final URI SOSNS = CommonNamespaces.SOSNS;
107    
108        protected static final URI DEEGREESOS = CommonNamespaces.DEEGREESOS;
109    
110        /**
111         * exports the SCS Capabilities
112         * 
113         * @param scsCapabilities
114         * @return
115         * @throws OGCWebServiceException
116         */
117        public static XMLFragment export( SOSCapabilities scsCapabilities )
118                                throws OGCWebServiceException {
119    
120            try {
121    
122                CapabilitiesDocument doc = new CapabilitiesDocument();
123    
124                doc.createEmptyDocument();
125    
126                Element root = doc.getRootElement();
127                XMLTools.appendNSBinding( root, CommonNamespaces.SOS_PREFIX.toLowerCase(), CommonNamespaces.SOSNS );
128    
129                // sets the version
130                root.setAttribute( "version", scsCapabilities.getVersion() );
131    
132                // sets the updateSsequence
133                root.setAttribute( "updateSequence", scsCapabilities.getUpdateSequence() );
134    
135                // appends the ServiceIdentification
136                ServiceIdentification serviceIdentification = scsCapabilities.getServiceIdentification();
137                if ( serviceIdentification != null ) {
138                    appendServiceIdentification( root, serviceIdentification );
139                }
140    
141                // appends the ServiceProvider
142                ServiceProvider serviceProvider = scsCapabilities.getServiceProvider();
143                if ( serviceProvider != null ) {
144                    appendServiceProvider( root, serviceProvider );
145                }
146    
147                // appends the OpertionsMetadata
148                OperationsMetadata operationsMetadata = scsCapabilities.getOperationsMetadata();
149                if ( operationsMetadata != null ) {
150                    appendOperationsMetadata( root, operationsMetadata );
151                }
152    
153                // appends the PlatformList
154                ArrayList platformList = scsCapabilities.getPlatformList();
155                if ( platformList != null ) {
156                    appendPlatformList( root, platformList );
157                }
158    
159                // appends the SensorList
160                ArrayList sensorList = scsCapabilities.getSensorList();
161                if ( sensorList != null ) {
162                    appendSensorList( root, sensorList );
163                }
164    
165                return doc;
166    
167            } catch ( Exception e ) {
168                LOG.logError( e.getMessage(), e );
169                throw new OGCWebServiceException( "scs webservice failure" );
170            }
171    
172        }
173    
174        /**
175         * 
176         * @param describePlatformResult
177         * @return
178         * @throws OGCWebServiceException
179         */
180        public static XMLFragment export( DescribePlatformResult describePlatformResult )
181                                throws OGCWebServiceException {
182    
183            PlatformDescriptionDocument scsDocument = new PlatformDescriptionDocument();
184    
185            // erstellt ein leeres Dokument wie in dem Template angegeben
186            try {
187                scsDocument.createEmptyDocument();
188    
189                Element root = scsDocument.getRootElement();
190                XMLTools.appendNSBinding( root, CommonNamespaces.GML_PREFIX.toLowerCase(), CommonNamespaces.GMLNS );
191                Document doc = root.getOwnerDocument();
192    
193                PlatformMetadata[] platformMetadata = describePlatformResult.getPlatforms();
194    
195                for ( int i = 0; i < platformMetadata.length; i++ ) {
196    
197                    root.appendChild( appendPlatform( platformMetadata[i], doc ) );
198                }
199    
200                return scsDocument;
201    
202            } catch ( Exception e ) {
203                LOG.logError( e.getMessage(), e );
204                throw new OGCWebServiceException( "sos webservice failure" );
205            }
206        }
207    
208        /**
209         * 
210         * @param describeSensorResult
211         * @return
212         * @throws OGCWebServiceException
213         */
214        public static XMLFragment export( DescribeSensorResult describeSensorResult )
215                                throws OGCWebServiceException {
216    
217            try {
218    
219                SensorDescriptionDocument scsDocument = new SensorDescriptionDocument();
220    
221                scsDocument.createEmptyDocument();
222    
223                Element root = scsDocument.getRootElement();
224                XMLTools.appendNSBinding( root, CommonNamespaces.GML_PREFIX.toLowerCase(), CommonNamespaces.GMLNS );
225    
226                Document doc = root.getOwnerDocument();
227    
228                SensorMetadata[] sensorMetadata = describeSensorResult.getSensors();
229    
230                for ( int i = 0; i < sensorMetadata.length; i++ ) {
231                    root.appendChild( appendSensor( sensorMetadata[i], doc ) );
232                }
233    
234                return scsDocument;
235    
236            } catch ( Exception e ) {
237                e.printStackTrace();
238                throw new OGCWebServiceException( "sos webservice failure" );
239            }
240        }
241    
242        /**
243         * 
244         * @param getObservationResult
245         * @return
246         * @throws OGCWebServiceException
247         */
248        public static XMLFragment export( GetObservationResult getObservationResult )
249                                throws OGCWebServiceException {
250    
251            GetObservationDocument scsDocument = new GetObservationDocument();
252    
253            try {
254                scsDocument.createEmptyDocument();
255    
256                Element root = scsDocument.getRootElement();
257                Document doc = root.getOwnerDocument();
258    
259                // TODO add boundedBy
260                Element boundedBy = doc.createElement( "gml:boundedBy" );
261                root.appendChild( boundedBy );
262    
263                Element leer = doc.createElement( "gml:Null" );
264                boundedBy.appendChild( leer );
265    
266                leer.appendChild( doc.createTextNode( "unknown" ) );
267    
268                Element observationMembers = doc.createElement( "om:observationMembers" );
269                root.appendChild( observationMembers );
270    
271                // add observation
272                appendObservationArrays( getObservationResult.getObservations(), observationMembers, doc );
273    
274                return scsDocument;
275    
276            } catch ( Exception e ) {
277                LOG.logError( e.getMessage(), e );
278                throw new OGCWebServiceException( "sos webservice failure" );
279            }
280        }
281    
282        /**
283         * appends ObservationArrays
284         * 
285         * @param observationArrays
286         * @param element
287         * @param doc
288         */
289        private static void appendObservationArrays( ObservationArray[] observationArrays, Element element, Document doc ) {
290            if ( observationArrays == null ) {
291                return;
292            }
293            if ( element == null ) {
294                return;
295            }
296            if ( doc == null ) {
297                return;
298            }
299    
300            for ( int i = 0; i < observationArrays.length; i++ ) {
301    
302                Element observationArray = doc.createElement( "om:ObservationArray" );
303                element.appendChild( observationArray );
304    
305                // TODO add boundedBy
306                Element boundedBy = doc.createElement( "gml:boundedBy" );
307                observationArray.appendChild( boundedBy );
308    
309                Element boundingBox = doc.createElement( "gml:boundingBox" );
310                boundedBy.appendChild( boundingBox );
311    
312                Element coordMin = doc.createElement( "gml:coord" );
313                boundingBox.appendChild( coordMin );
314    
315                Element minX = doc.createElement( "gml:X" );
316                coordMin.appendChild( minX );
317    
318                minX.appendChild( doc.createTextNode( "" + observationArrays[i].getBoundedBy().getMin().getX() ) );
319    
320                Element minY = doc.createElement( "gml:Y" );
321                coordMin.appendChild( minY );
322    
323                minY.appendChild( doc.createTextNode( "" + observationArrays[i].getBoundedBy().getMin().getY() ) );
324    
325                Element coordMax = doc.createElement( "gml:coord" );
326                boundingBox.appendChild( coordMax );
327    
328                Element maxX = doc.createElement( "gml:X" );
329                coordMax.appendChild( maxX );
330    
331                maxX.appendChild( doc.createTextNode( "" + observationArrays[i].getBoundedBy().getMax().getX() ) );
332    
333                Element maxY = doc.createElement( "gml:Y" );
334                coordMax.appendChild( maxY );
335    
336                maxY.appendChild( doc.createTextNode( "" + observationArrays[i].getBoundedBy().getMax().getY() ) );
337    
338                // TODO add using
339                Element using = doc.createElement( "om:using" );
340                observationArray.appendChild( using );
341    
342                Element observationMembers = doc.createElement( "om:observationMembers" );
343                observationArray.appendChild( observationMembers );
344    
345                appendObservations( observationArrays[i].getObservations(), observationMembers, doc );
346    
347            }
348    
349        }
350    
351        /**
352         * appends Observations
353         * 
354         * @param observations
355         * @param element
356         * @param doc
357         */
358        private static void appendObservations( Observation[] observations, Element element, Document doc ) {
359            if ( observations == null ) {
360                return;
361            }
362            if ( element == null ) {
363                return;
364            }
365            if ( doc == null ) {
366                return;
367            }
368    
369            for ( int i = 0; i < observations.length; i++ ) {
370    
371                Element observation = doc.createElement( "gml:Observation" );
372                element.appendChild( observation );
373    
374                // add timeStamp
375                Element timeStamp = doc.createElement( "gml:timeStamp" );
376                observation.appendChild( timeStamp );
377    
378                Element timeInstant = doc.createElement( "gml:TimeInstant" );
379                timeStamp.appendChild( timeInstant );
380    
381                Element timePosition = doc.createElement( "gml:timePosition" );
382                timeInstant.appendChild( timePosition );
383    
384                timePosition.appendChild( doc.createTextNode( observations[i].getTimeStamp() ) );
385    
386                // add resultOf
387                Element resultOf = doc.createElement( "gml:resultOf" );
388                observation.appendChild( resultOf );
389    
390                Element quantityList = doc.createElement( "gml:QuantityList" );
391                resultOf.appendChild( quantityList );
392    
393                String ro = observations[i].getResultOf();
394                if ( ro != null ) {
395                    quantityList.appendChild( doc.createTextNode( ro ) );
396                }
397    
398            }
399    
400        }
401    
402        /**
403         * appends a PlatformList used by getCapabilities
404         * 
405         * @param root
406         * @param platformList
407         * 
408         */
409        private static void appendPlatformList( Element root, ArrayList pl ) {
410    
411            if ( pl == null ) {
412                return;
413            }
414    
415            // XmlNode nn = new XmlNode(root);
416            // nn.appendDomChild(XmlNode.Element, SCSNS, "sos:PlatformList", null);
417    
418            Element element = XMLTools.appendElement( root, SOSNS, "sos:PlatformList" );
419    
420            // XmlNode platformListNode = new XmlNode( nn );
421    
422            for ( int i = 0; i < pl.size(); i++ ) {
423    
424                // XmlNode n = new XmlNode(platformListNode);
425                // n.appendDomChild(XmlNode.Element, SCSNS, "sos:Platform",null);
426                // XmlNode platformNode =new XmlNode( n );
427    
428                Element elem = XMLTools.appendElement( element, SOSNS, "sos:Platform" );
429                elem.setAttribute( "Id", ( (Platform) pl.get( i ) ).getId() );
430    
431                // platformNode.appendDomChild( XmlNode.Attribute, null, "Id", ""
432                // + ((Platform) pl.get(i)).getId());
433    
434                // platformNode.appendDomChild( XmlNode.Attribute, null, "Description",
435                // "" + ((Platform) pl.get(i)).getDescription());
436    
437                elem.setAttribute( "Description", ( (Platform) pl.get( i ) ).getDescription() );
438            }
439        }
440    
441        /**
442         * appends a sensor list used by getCapabilities
443         * 
444         * @param root
445         * @param sensorList
446         * 
447         */
448        private static void appendSensorList( Element root, ArrayList sl ) {
449            if ( sl == null ) {
450                return;
451            }
452    
453            Element element = XMLTools.appendElement( root, SOSNS, "sos:SensorList" );
454    
455            for ( int i = 0; i < sl.size(); i++ ) {
456                Element elem = XMLTools.appendElement( element, SOSNS, "sos:Sensor" );
457                elem.setAttribute( "Id", ( (Sensor) sl.get( i ) ).getId() );
458                elem.setAttribute( "Description", ( (Sensor) sl.get( i ) ).getDescription() );
459    
460            }
461        }
462    
463        /**
464         * returns a platform element
465         * 
466         * @param actPlatform
467         * @param doc
468         * @return a platform element
469         */
470        private static Element appendPlatform( PlatformMetadata actPlatform, Document doc ) {
471    
472            if ( actPlatform == null ) {
473                return null;
474            }
475    
476            Element platform = doc.createElement( "sml:Platform" );
477    
478            appendIdentifiedAs( actPlatform.getIdentifiedAs(), platform, doc );
479    
480            appendClassifiedAs( actPlatform.getClassifiedAs(), platform, doc );
481    
482            appendAttachedTo( actPlatform, platform, doc );
483    
484            appendHasCRS( actPlatform.getHasCRS(), platform, doc );
485    
486            appendDescribedBy( actPlatform, platform, doc );
487    
488            appendLocatedUsing( actPlatform.getLocatedUsing(), platform, doc );
489    
490            appendCarries( actPlatform.getCarries(), platform, doc );
491    
492            return platform;
493        }
494    
495        /**
496         * 
497         * @param actSensor
498         * @param doc
499         * @return
500         */
501        private static Element appendSensor( SensorMetadata actSensor, Document doc ) {
502            if ( actSensor == null ) {
503                return null;
504            }
505    
506            Element sensor = doc.createElement( "sml:Sensor" );
507    
508            appendIdentifiedAs( actSensor.getIdentifiedAs(), sensor, doc );
509    
510            appendClassifiedAs( actSensor.getClassifiedAs(), sensor, doc );
511    
512            appendAttachedTo( actSensor, sensor, doc );
513    
514            appendHasCRS( actSensor.getHasCRS(), sensor, doc );
515    
516            appendDescribedBy( actSensor, sensor, doc );
517    
518            appendLocatedUsing( actSensor.getLocatedUsing(), sensor, doc );
519    
520            appendMeasures( actSensor.getMeasures(), sensor, doc );
521    
522            return sensor;
523        }
524    
525        /**
526         * appends a IdentifiedAs Node
527         * 
528         * @param actii
529         *            blah blah. Cannot be null.
530         * @param element
531         * @param doc
532         */
533        private static void appendIdentifiedAs( Identifier[] actidentifier, Element element, Document doc ) {
534            if ( actidentifier == null ) {
535                return;
536            }
537    
538            for ( int i = 0; i < actidentifier.length; i++ ) {
539                int type = actidentifier[i].getIdentifierType();
540    
541                Element identifiedAs = doc.createElement( "sml:identifiedAs" );
542                Element identifier = doc.createElement( "sml:Identifier" );
543    
544                // is required; no check
545                identifier.appendChild( doc.createTextNode( actidentifier[i].getIdentifierValue() ) );
546    
547                // is optional; but type must be checked
548                if ( type == 1 )
549                    identifier.setAttribute( "type", "shortName" );
550                if ( type == 2 )
551                    identifier.setAttribute( "type", "longName" );
552                if ( type == 3 )
553                    identifier.setAttribute( "type", "serialNumber" );
554                if ( type == 4 )
555                    identifier.setAttribute( "type", "modelNumber" );
556                if ( type == 5 )
557                    identifier.setAttribute( "type", "missionNumber" );
558                if ( type == 6 )
559                    identifier.setAttribute( "type", "partNumber" );
560    
561                // is optional; check
562                if ( actidentifier[i].getIdentifierCodeSpace() != null )
563                    identifier.setAttribute( "codeSpace", actidentifier[i].getIdentifierCodeSpace() );
564    
565                identifiedAs.appendChild( identifier );
566                element.appendChild( identifiedAs );
567            }
568    
569        }
570    
571        /**
572         * 
573         * @param object
574         * @param doc
575         * @return
576         */
577        private static void appendAttachedTo( Object object, Element element, Document doc ) {
578    
579            // optional; check
580            if ( ( (ComponentMetadata) object ).getAttachedTo() != null ) {
581                Element attachedTo = doc.createElement( "sml:attachedTo" );
582    
583                Element component = doc.createElement( "sml:Component" );
584                attachedTo.appendChild( component );
585    
586                component.appendChild( doc.createTextNode( ( (ComponentMetadata) object ).getAttachedTo() ) );
587                element.appendChild( attachedTo );
588            }
589        }
590    
591        /**
592         * 
593         * @param object
594         * @param doc
595         * @return
596         */
597        private static void appendClassifiedAs( Classifier[] actClassifier, Element element, Document doc ) {
598            if ( actClassifier == null ) {
599                return;
600            }
601    
602            for ( int i = 0; i < actClassifier.length; i++ ) {
603    
604                Element classifiedAs = doc.createElement( "sml:classifiedAs" );
605                Element classifier = doc.createElement( "sml:Classifier" );
606                classifiedAs.appendChild( classifier );
607    
608                // required; no check
609                classifier.setAttribute( "type", actClassifier[i].getType() );
610    
611                // required; no check
612                classifier.appendChild( doc.createTextNode( actClassifier[i].getValue() ) );
613                // optional; check
614                if ( actClassifier[i].getCodeSpace() != null ) {
615                    classifier.setAttribute( "codeSpace", actClassifier[i].getCodeSpace() );
616                }
617    
618                element.appendChild( classifiedAs );
619            }
620    
621        }
622    
623        private static void appendDerivedFrom( ResponseModel[] responseModels, Element element, Document doc ) {
624            if ( responseModels == null ) {
625                return;
626            }
627    
628            for ( int i = 0; i < responseModels.length; i++ ) {
629    
630                Element derivedFrom = doc.createElement( "sml:derivedFrom" );
631                element.appendChild( derivedFrom );
632    
633                Element responseModel = doc.createElement( "sml:ResponseModel" );
634                derivedFrom.appendChild( responseModel );
635    
636                // appends identifiedAs
637                appendIdentifiedAs( responseModels[i].getIdentifiedAs(), responseModel, doc );
638    
639                // appends classifiedAs
640                appendClassifiedAs( responseModels[i].getClassifiedAs(), responseModel, doc );
641    
642                // appends description
643                appendDescription( responseModels[i].getDescription(), responseModel, doc );
644    
645                appendUsesParametersFromDerivedFrom( responseModels[i].getUsesParameters(), responseModel, doc );
646    
647            }
648    
649        }
650    
651        /**
652         * appends a hasCRS node
653         * 
654         * @param object
655         * @param element
656         * @param doc
657         */
658        private static void appendHasCRS( EngineeringCRS engineeringCRS, Element element, Document doc ) {
659            if ( engineeringCRS == null ) {
660                return;
661            }
662    
663            Element hasCRS = doc.createElement( "sml:hasCRS" );
664            element.appendChild( hasCRS );
665            appendEngineeringCRS( engineeringCRS, hasCRS, doc );
666    
667        }
668    
669        private static void appendEngineeringCRS( EngineeringCRS engineeringCRS, Element element, Document doc ) {
670    
671            if ( engineeringCRS == null ) {
672                return;
673            }
674    
675            Element engineeringCRSEle = doc.createElement( "gml:EngineeringCRS" );
676            element.appendChild( engineeringCRSEle );
677            Element srsName = doc.createElement( "gml:srsName" );
678    
679            srsName.appendChild( doc.createTextNode( engineeringCRS.getSrsName() ) );
680    
681            engineeringCRSEle.appendChild( srsName );
682    
683        }
684    
685        private static void appendCoordinateReferenceSystem( CoordinateReferenceSystem crs, Element element, Document doc ) {
686    
687            if ( crs == null ) {
688                return;
689            }
690    
691            if ( crs instanceof GeographicCRS ) {
692                Element geographicCRS = doc.createElement( "gml:GeographicCRS" );
693                element.appendChild( geographicCRS );
694                Element srsName = doc.createElement( "gml:srsName" );
695    
696                srsName.appendChild( doc.createTextNode( crs.getSrsName() ) );
697    
698                geographicCRS.appendChild( srsName );
699            }
700            if ( crs instanceof ProjectedCRS ) {
701                Element projectedCRS = doc.createElement( "gml:ProjectedCRS" );
702                element.appendChild( projectedCRS );
703                Element srsName = doc.createElement( "gml:srsName" );
704    
705                srsName.appendChild( doc.createTextNode( crs.getSrsName() ) );
706    
707                projectedCRS.appendChild( srsName );
708            }
709    
710        }
711    
712        /**
713         * 
714         * @param object
715         * @param doc
716         * @return
717         */
718        private static void appendDescribedBy( Object object, Element element, Document doc ) {
719    
720            if ( ( (ComponentMetadata) object ).getDescribedBy() != null ) {
721                Element describedBy = doc.createElement( "sml:describedBy" );
722    
723                Element componentDescription = doc.createElement( "sml:ComponentDescription" );
724                describedBy.appendChild( componentDescription );
725    
726                if ( ( ( (ComponentMetadata) object ).getDescribedBy() ).getId() != null ) {
727                    componentDescription.setAttribute( "id", ( ( (ComponentMetadata) object ).getDescribedBy() ).getId() );
728                }
729    
730                // append description
731                appendDescription( ( ( (ComponentMetadata) object ).getDescribedBy() ).getDescription(),
732                                   componentDescription, doc );
733    
734                // append operatedBy
735                CitedResponsibleParty[] operatedBy = ( ( (ComponentMetadata) object ).getDescribedBy() ).getOperatedBy();
736                for ( int i = 0; i < operatedBy.length; i++ ) {
737                    appendOperatedBy( operatedBy[i], componentDescription, doc );
738                }
739    
740                // append operatedBy
741                CitedResponsibleParty[] manufactedBy = ( ( (ComponentMetadata) object ).getDescribedBy() ).getManufacturedBy();
742                for ( int i = 0; i < manufactedBy.length; i++ ) {
743                    appendManufactedBy( manufactedBy[i], componentDescription, doc );
744                }
745    
746                // append operatedBy
747                CitedResponsibleParty[] deployedBy = ( ( (ComponentMetadata) object ).getDescribedBy() ).getDeployedBy();
748                for ( int i = 0; i < deployedBy.length; i++ ) {
749                    appendDeployedBy( deployedBy[i], componentDescription, doc );
750                }
751    
752                // append reference
753                Reference[] reference = ( ( (ComponentMetadata) object ).getDescribedBy() ).getReference();
754                if ( ( reference != null ) && ( reference.length > 0 ) ) {
755                    Element ref = doc.createElement( "sml:reference" );
756                    componentDescription.appendChild( ref );
757    
758                    for ( int i = 0; i < reference.length; i++ ) {
759                        if ( reference[i].isOnLineResource() ) {
760    
761                            appendOnlineResource( reference[i].getOnLineResource(), ref, doc );
762                        }
763                        if ( reference[i].isCitation() ) {
764    
765                        }
766                    }
767                }
768                element.appendChild( describedBy );
769            }
770    
771        }
772    
773        private static void appendLocatedUsing( LocationModel[] locatedUsingList, Element element, Document doc ) {
774    
775            if ( locatedUsingList == null ) {
776                return;
777            }
778    
779            Element locatedUsing = doc.createElement( "sml:locatedUsing" );
780            element.appendChild( locatedUsing );
781    
782            // process all locatedUsing objects
783            for ( int i = 0; i < locatedUsingList.length; i++ ) {
784    
785                // is GeoPositionModel
786                if ( locatedUsingList[i] instanceof GeoPositionModel ) {
787                    Element geoPositionModel = doc.createElement( "sml:GeoPositionModel" );
788                    locatedUsing.appendChild( geoPositionModel );
789    
790                    if ( ( (GeoPositionModel) locatedUsingList[i] ).getId() != null ) {
791                        geoPositionModel.setAttribute( "id", ( (GeoPositionModel) locatedUsingList[i] ).getId() );
792                    }
793    
794                    appendIdentifiedAs( ( (GeoPositionModel) locatedUsingList[i] ).getIdentifiedAs(), geoPositionModel, doc );
795    
796                    appendClassifiedAs( ( (GeoPositionModel) locatedUsingList[i] ).getClassifiedAs(), geoPositionModel, doc );
797    
798                    appendDescription( ( (GeoPositionModel) locatedUsingList[i] ).getDescription(), geoPositionModel, doc );
799    
800                    // append sourceCRS
801                    Element sourceCRS = doc.createElement( "sml:sourceCRS" );
802                    geoPositionModel.appendChild( sourceCRS );
803                    appendEngineeringCRS( ( (GeoPositionModel) locatedUsingList[i] ).getSourceCRS(), sourceCRS, doc );
804    
805                    // append referenceCRS
806                    Element referenceCRS = doc.createElement( "sml:referenceCRS" );
807                    geoPositionModel.appendChild( referenceCRS );
808                    appendCoordinateReferenceSystem( ( (GeoPositionModel) locatedUsingList[i] ).getReferenceCRS(),
809                                                     referenceCRS, doc );
810    
811                    // append usesParameters
812                    appendUsesParametersFromGeoLocation(
813                                                         ( (GeoPositionModel) locatedUsingList[i] ).getUsesParametersObjects(),
814                                                         geoPositionModel, doc );
815    
816                }
817            }
818    
819        }
820    
821        private static void appendUsesParametersFromGeoLocation( Object[] objects, Element element, Document doc ) {
822    
823            if ( objects == null ) {
824                return;
825            }
826    
827            for ( int i = 0; i < objects.length; i++ ) {
828                // is GeoLocation
829                if ( objects[i] instanceof GeoLocation ) {
830                    Element usesParameters = doc.createElement( "sml:usesParameters" );
831                    element.appendChild( usesParameters );
832    
833                    Element geoLocation = doc.createElement( "sml:GeoLocation" );
834                    usesParameters.appendChild( geoLocation );
835    
836                    geoLocation.setAttribute( "id", ( (GeoLocation) objects[i] ).getId() );
837    
838                    // appends latitude
839                    Element latitude = doc.createElement( "sml:latitude" );
840                    geoLocation.appendChild( latitude );
841                    appendQuantity( ( (GeoLocation) objects[i] ).getLatitude(), latitude, doc );
842    
843                    // appends longitude
844                    Element longitude = doc.createElement( "sml:longitude" );
845                    geoLocation.appendChild( longitude );
846                    appendQuantity( ( (GeoLocation) objects[i] ).getLongitude(), longitude, doc );
847    
848                    // appends altitude
849                    if ( ( (GeoLocation) objects[i] ).getAltitude() != null ) {
850                        Element altitude = doc.createElement( "sml:altitude" );
851                        geoLocation.appendChild( altitude );
852                        appendQuantity( ( (GeoLocation) objects[i] ).getAltitude(), altitude, doc );
853                    }
854    
855                    // appends trueHeading
856                    if ( ( (GeoLocation) objects[i] ).getTrueHeading() != null ) {
857                        Element trueHeading = doc.createElement( "sml:trueHeading" );
858                        geoLocation.appendChild( trueHeading );
859                        appendQuantity( ( (GeoLocation) objects[i] ).getTrueHeading(), trueHeading, doc );
860                    }
861    
862                    // appends speed
863                    if ( ( (GeoLocation) objects[i] ).getSpeed() != null ) {
864                        Element speed = doc.createElement( "sml:speed" );
865                        geoLocation.appendChild( speed );
866                        appendQuantity( ( (GeoLocation) objects[i] ).getSpeed(), speed, doc );
867                    }
868    
869                }
870    
871            }
872        }
873    
874        private static void appendUsesParametersFromDerivedFrom( Object[] objects, Element element, Document doc ) {
875            if ( objects != null ) {
876                for ( int i = 0; i < objects.length; i++ ) {
877                    // is GeoLocation
878                    if ( objects[i] instanceof BasicResponse ) {
879                        Element usesParameters = doc.createElement( "sml:usesParameters" );
880                        element.appendChild( usesParameters );
881    
882                        Element basicResponse = doc.createElement( "sml:BasicResponse" );
883                        usesParameters.appendChild( basicResponse );
884    
885                        Element resolution = doc.createElement( "sml:resolution" );
886                        basicResponse.appendChild( resolution );
887    
888                        Element typedQuantity = doc.createElement( "sml:TypedQuantity" );
889                        resolution.appendChild( typedQuantity );
890    
891                        typedQuantity.appendChild( doc.createTextNode( ""
892                                                                       + ( (BasicResponse) objects[i] ).getResolution().getValue() ) );
893    
894                        // sets required attrib type
895                        typedQuantity.setAttribute( "type",
896                                                    ( (BasicResponse) objects[i] ).getResolution().getType().toString() );
897    
898                        // sets optional attrib codeSpace
899                        if ( ( (BasicResponse) objects[i] ).getResolution().getCodeSpace() != null ) {
900                            typedQuantity.setAttribute(
901                                                        "codeSpace",
902                                                        ( (BasicResponse) objects[i] ).getResolution().getCodeSpace().toString() );
903                        }
904    
905                        // sets optional attrib fixed
906                        if ( !( (BasicResponse) objects[i] ).getResolution().isFixed() ) {
907                            typedQuantity.setAttribute( "fixed", "false" );
908                        }
909    
910                        // sets optional attrib uom
911                        if ( ( (BasicResponse) objects[i] ).getResolution().getUom() != null ) {
912                            typedQuantity.setAttribute( "uom",
913                                                        ( (BasicResponse) objects[i] ).getResolution().getUom().toString() );
914                        }
915    
916                        // sets optional attrib min
917                        if ( !Double.isNaN( ( (BasicResponse) objects[i] ).getResolution().getMin() ) ) {
918                            typedQuantity.setAttribute( "min", "" + ( (BasicResponse) objects[i] ).getResolution().getMin() );
919                        }
920    
921                        // sets optional attrib max
922                        if ( !Double.isNaN( ( (BasicResponse) objects[i] ).getResolution().getMax() ) ) {
923                            typedQuantity.setAttribute( "max", "" + ( (BasicResponse) objects[i] ).getResolution().getMax() );
924                        }
925    
926                        // sets optional attrib id
927                        if ( ( (BasicResponse) objects[i] ).getResolution().getId() != null ) {
928                            typedQuantity.setAttribute( "id", ( (BasicResponse) objects[i] ).getResolution().getId() );
929                        }
930    
931                    }
932    
933                }
934    
935            }
936        }
937    
938        private static void appendQuantity( Quantity quantity, Element element, Document doc ) {
939    
940            if ( quantity == null ) {
941                return;
942            }
943    
944            Element quantityEle = doc.createElement( "sml:Quantity" );
945            element.appendChild( quantityEle );
946            quantityEle.appendChild( doc.createTextNode( "" + quantity.getValue() ) );
947    
948            // appends uom
949            if ( quantity.getUom() != null ) {
950                quantityEle.setAttribute( "uom", quantity.getUom().toString() );
951            }
952    
953            // appends fixed
954            if ( quantity.isFixed() ) {
955                quantityEle.setAttribute( "fixed", "true" );
956            }
957            if ( !quantity.isFixed() ) {
958                quantityEle.setAttribute( "fixed", "false" );
959            }
960    
961            // appends min
962            if ( !Double.isNaN( quantity.getMin() ) ) {
963                quantityEle.setAttribute( "min", "" + quantity.getMin() );
964            }
965    
966            // appends max
967            if ( !Double.isNaN( quantity.getMax() ) ) {
968                quantityEle.setAttribute( "max", "" + quantity.getMax() );
969            }
970    
971        }
972    
973        /**
974         * 
975         * @param description
976         * @param element
977         * @param doc
978         */
979        private static void appendDescription( Discussion[] description, Element element, Document doc ) {
980    
981            if ( description == null ) {
982                return;
983            }
984    
985            for ( int i = 0; i < description.length; i++ ) {
986    
987                Element desc = doc.createElement( "sml:description" );
988    
989                desc.appendChild( doc.createTextNode( description[i].getValue() ) );
990    
991                if ( description[i].getId() != null ) {
992                    desc.setAttribute( "id", description[i].getId() );
993                }
994                if ( description[i].getTopic() != null ) {
995                    desc.setAttribute( "topic", description[i].getTopic().toString() );
996                }
997                if ( description[i].getCodeSpace() != null ) {
998                    desc.setAttribute( "codeSpace", description[i].getCodeSpace().toString() );
999    
1000                }
1001    
1002                element.appendChild( desc );
1003            }
1004    
1005        }
1006    
1007        /**
1008         * 
1009         * @param onlineResource
1010         * @param element
1011         * @param doc
1012         */
1013        private static void appendOnlineResource( OnlineResource onlineResource, Element element, Document doc ) {
1014    
1015            if ( onlineResource == null ) {
1016                return;
1017            }
1018    
1019            Element onlineRes = doc.createElement( "iso19115:CI_OnlineResource" );
1020    
1021            // append linkage
1022            Element linkage = doc.createElement( "iso19115:linkage" );
1023            linkage.appendChild( doc.createTextNode( onlineResource.getLinkage().getHref().toString() ) );
1024            onlineRes.appendChild( linkage );
1025    
1026            // append function
1027            if ( onlineResource.getFunctionCode().getValue() != null ) {
1028                Element function = doc.createElement( "iso19115:function" );
1029                function.appendChild( doc.createTextNode( onlineResource.getFunctionCode().getValue() ) );
1030                onlineRes.appendChild( function );
1031            }
1032    
1033            // append protocol
1034            if ( onlineResource.getProtocol() != null ) {
1035                Element protocol = doc.createElement( "iso19115:protocol" );
1036                protocol.appendChild( doc.createTextNode( onlineResource.getProtocol() ) );
1037                onlineRes.appendChild( protocol );
1038            }
1039    
1040            // append applicationProfile
1041            if ( onlineResource.getApplicationProfile() != null ) {
1042                Element applicationProfile = doc.createElement( "iso19115:applicationProfile" );
1043                applicationProfile.appendChild( doc.createTextNode( onlineResource.getApplicationProfile() ) );
1044                onlineRes.appendChild( applicationProfile );
1045            }
1046    
1047            // append name
1048            if ( onlineResource.getOnlineResourceName() != null ) {
1049                Element name = doc.createElement( "iso19115:name" );
1050                name.appendChild( doc.createTextNode( onlineResource.getOnlineResourceName() ) );
1051                onlineRes.appendChild( name );
1052            }
1053    
1054            // append description
1055            if ( onlineResource.getOnlineResourceDescription() != null ) {
1056                Element description = doc.createElement( "iso19115:description" );
1057                description.appendChild( doc.createTextNode( onlineResource.getOnlineResourceDescription() ) );
1058                onlineRes.appendChild( description );
1059            }
1060    
1061            element.appendChild( onlineRes );
1062    
1063        }
1064    
1065        private static void appendOperatedBy( CitedResponsibleParty responsibleParty, Element element, Document doc ) {
1066    
1067            if ( responsibleParty == null ) {
1068                return;
1069            }
1070    
1071            Element operatedBy = doc.createElement( "sml:operatedBy" );
1072            element.appendChild( operatedBy );
1073            appendResponsibleParty( responsibleParty, operatedBy, doc );
1074    
1075        }
1076    
1077        private static void appendManufactedBy( CitedResponsibleParty responsibleParty, Element element, Document doc ) {
1078    
1079            if ( responsibleParty == null ) {
1080                return;
1081            }
1082    
1083            Element manufactedBy = doc.createElement( "sml:manufactedBy" );
1084            element.appendChild( manufactedBy );
1085            appendResponsibleParty( responsibleParty, manufactedBy, doc );
1086    
1087        }
1088    
1089        private static void appendDeployedBy( CitedResponsibleParty responsibleParty, Element element, Document doc ) {
1090    
1091            if ( responsibleParty == null ) {
1092                return;
1093            }
1094    
1095            Element deployedBy = doc.createElement( "sml:deployedBy" );
1096            element.appendChild( deployedBy );
1097            appendResponsibleParty( responsibleParty, deployedBy, doc );
1098    
1099        }
1100    
1101        private static void appendContactInfo( ContactInfo contact, Element element, Document doc ) {
1102    
1103            if ( contact == null ) {
1104                return;
1105            }
1106    
1107            Element cont = doc.createElement( "iso19115:contactInfo" );
1108            element.appendChild( cont );
1109    
1110            if ( contact.getPhone() != null ) {
1111                appendPhone( contact.getPhone(), cont, doc );
1112            }
1113    
1114            if ( contact.getAddress() != null ) {
1115                appendAddress( contact.getAddress(), cont, doc );
1116            }
1117    
1118            if ( contact.getOnLineResource() != null ) {
1119                appendOnlineResource( contact.getOnLineResource(), cont, doc );
1120            }
1121    
1122            if ( contact.getHoursOfService() != null ) {
1123                Element hours = doc.createElement( "iso19115:hoursOfService" );
1124                cont.appendChild( hours );
1125                hours.appendChild( doc.createTextNode( contact.getHoursOfService() ) );
1126            }
1127    
1128            if ( contact.getContactInstructions() != null ) {
1129                Element instr = doc.createElement( "iso19115:contactInstructions" );
1130                cont.appendChild( instr );
1131                instr.appendChild( doc.createTextNode( contact.getContactInstructions() ) );
1132            }
1133    
1134        }
1135    
1136        private static void appendPhone( Phone phone, Element element, Document doc ) {
1137    
1138            if ( phone == null ) {
1139                return;
1140            }
1141    
1142            Element phoneEle = doc.createElement( "iso19115:phone" );
1143            element.appendChild( phoneEle );
1144    
1145            String[] voice = phone.getVoice();
1146            if ( ( voice != null ) && ( voice.length > 0 ) ) {
1147                for ( int i = 0; i < voice.length; i++ ) {
1148                    Element actVoice = doc.createElement( "iso19115:voice" );
1149                    phoneEle.appendChild( actVoice );
1150                    actVoice.appendChild( doc.createTextNode( voice[i] ) );
1151                }
1152            }
1153    
1154            String[] fac = phone.getFacsimile();
1155            if ( ( fac != null ) && ( fac.length > 0 ) ) {
1156                for ( int i = 0; i < fac.length; i++ ) {
1157                    Element actFac = doc.createElement( "iso19115:facsimile" );
1158                    phoneEle.appendChild( actFac );
1159                    actFac.appendChild( doc.createTextNode( fac[i] ) );
1160                }
1161            }
1162    
1163        }
1164    
1165        private static void appendAddress( Address address, Element element, Document doc ) {
1166    
1167            if ( address == null ) {
1168                return;
1169            }
1170    
1171            Element addr = doc.createElement( "iso19115:address" );
1172            element.appendChild( addr );
1173    
1174            if ( address.getCity() != null ) {
1175                Element city = doc.createElement( "iso19115:city" );
1176                addr.appendChild( city );
1177                city.appendChild( doc.createTextNode( address.getCity() ) );
1178            }
1179    
1180            if ( address.getAdministrativeArea() != null ) {
1181                Element administrativeArea = doc.createElement( "iso19115:administrativeArea" );
1182                addr.appendChild( administrativeArea );
1183                administrativeArea.appendChild( doc.createTextNode( address.getAdministrativeArea() ) );
1184            }
1185    
1186            if ( address.getPostalCode() != null ) {
1187                Element postalCode = doc.createElement( "iso19115:postalCode" );
1188                addr.appendChild( postalCode );
1189                postalCode.appendChild( doc.createTextNode( address.getPostalCode() ) );
1190            }
1191    
1192            if ( address.getCountry() != null ) {
1193                Element country = doc.createElement( "iso19115:country" );
1194                addr.appendChild( country );
1195                country.appendChild( doc.createTextNode( address.getCountry() ) );
1196            }
1197    
1198            String[] deliveryPoints = address.getDeliveryPoint();
1199            for ( int i = 0; i < deliveryPoints.length; i++ ) {
1200                Element deliveryPoint = doc.createElement( "iso19115:deliveryPoint" );
1201                addr.appendChild( deliveryPoint );
1202                deliveryPoint.appendChild( doc.createTextNode( deliveryPoints[i] ) );
1203            }
1204    
1205            String[] electronicMailAddresses = address.getElectronicMailAddress();
1206            for ( int i = 0; i < electronicMailAddresses.length; i++ ) {
1207                Element electronicMailAddress = doc.createElement( "iso19115:electronicMailAddress" );
1208                addr.appendChild( electronicMailAddress );
1209                electronicMailAddress.appendChild( doc.createTextNode( electronicMailAddresses[i] ) );
1210            }
1211    
1212        }
1213    
1214        private static void appendResponsibleParty( CitedResponsibleParty responsibleParty, Element element, Document doc ) {
1215    
1216            if ( responsibleParty == null ) {
1217                return;
1218            }
1219    
1220            Element respParty = doc.createElement( "iso19115:CI_ResponsibleParty" );
1221            element.appendChild( respParty );
1222    
1223            // append IndividualName
1224            if ( responsibleParty.getIndividualName() != null ) {
1225                String[] individualNameList = responsibleParty.getIndividualName();
1226                for ( int i = 0; i < individualNameList.length; i++ ) {
1227                    Element individualName = doc.createElement( "iso19115:individualName" );
1228                    individualName.appendChild( doc.createTextNode( individualNameList[i] ) );
1229                    respParty.appendChild( individualName );
1230                }
1231            }
1232    
1233            // append OrganisationName
1234            if ( responsibleParty.getOrganisationName() != null ) {
1235                String[] organisationNameList = responsibleParty.getOrganisationName();
1236                for ( int i = 0; i < organisationNameList.length; i++ ) {
1237                    Element organisationName = doc.createElement( "iso19115:organisationName" );
1238                    organisationName.appendChild( doc.createTextNode( organisationNameList[i] ) );
1239                    respParty.appendChild( organisationName );
1240                }
1241            }
1242    
1243            // append PositionName
1244            if ( responsibleParty.getPositionName() != null ) {
1245                String[] positionNameList = responsibleParty.getPositionName();
1246                for ( int i = 0; i < positionNameList.length; i++ ) {
1247                    Element positionName = doc.createElement( "iso19115:positionName" );
1248                    positionName.appendChild( doc.createTextNode( positionNameList[i] ) );
1249                    respParty.appendChild( positionName );
1250                }
1251            }
1252    
1253            // append Role as codelist
1254    
1255            RoleCode[] roleList = responsibleParty.getRoleCode();
1256    
1257            for ( int i = 0; i < roleList.length; i++ ) {
1258                if ( roleList[i].getValue() != null ) {
1259                    Element role = doc.createElement( "iso19115:role" );
1260                    respParty.appendChild( role );
1261                    Element codeList = doc.createElement( "iso19115:CI_RoleCode_CodeList" );
1262                    role.appendChild( codeList );
1263                    codeList.appendChild( doc.createTextNode( roleList[i].getValue() ) );
1264                }
1265            }
1266    
1267            // append contact
1268            if ( responsibleParty.getContactInfo() != null ) {
1269                ContactInfo[] contactInfoList = responsibleParty.getContactInfo();
1270                for ( int i = 0; i < contactInfoList.length; i++ ) {
1271                    appendContactInfo( contactInfoList[i], respParty, doc );
1272                }
1273    
1274            }
1275    
1276        }
1277    
1278        private static void appendMeasures( Product[] products, Element element, Document doc ) {
1279    
1280            if ( products == null ) {
1281                return;
1282            }
1283    
1284            for ( int i = 0; i < products.length; i++ ) {
1285    
1286                Element measures = doc.createElement( "sml:measures" );
1287                Element product = doc.createElement( "sml:Product" );
1288                if ( products[i].getId() != null ) {
1289                    product.setAttribute( "id", products[i].getId() );
1290                }
1291                measures.appendChild( product );
1292    
1293                // appends identifiedAs
1294                appendIdentifiedAs( products[i].getIdentifiedAs(), product, doc );
1295    
1296                // appends classifiedAs
1297                appendClassifiedAs( products[i].getClassifiedAs(), product, doc );
1298    
1299                // appends description
1300                appendDescription( products[i].getDescription(), product, doc );
1301    
1302                // appends observable
1303                if ( products[i].getObservable() != null ) {
1304                    Element observable = doc.createElement( "sml:observable" );
1305                    product.appendChild( observable );
1306                    Element phenomenon = doc.createElement( "sml:Phenomenon" );
1307                    observable.appendChild( phenomenon );
1308    
1309                    if ( products[i].getObservable().getId() != null ) {
1310                        phenomenon.setAttribute( "id", products[i].getObservable().getId() );
1311                    }
1312    
1313                    if ( products[i].getObservable().getName() != null ) {
1314                        Element name = doc.createElement( "sml:name" );
1315                        phenomenon.appendChild( name );
1316                        name.appendChild( doc.createTextNode( products[i].getObservable().getName() ) );
1317                    }
1318    
1319                    if ( products[i].getObservable().getDefinition() != null ) {
1320                        Element description = doc.createElement( "sml:description" );
1321                        phenomenon.appendChild( description );
1322                        description.appendChild( doc.createTextNode( products[i].getObservable().getDefinition() ) );
1323                    }
1324                }
1325    
1326                // appends hasCRS
1327                if ( products[i].getHasCRS() != null ) {
1328                    appendHasCRS( products[i].getHasCRS(), product, doc );
1329                }
1330    
1331                // appends locatedUsing
1332                if ( products[i].getLocatedUsing() != null ) {
1333                    appendLocatedUsing( products[i].getLocatedUsing(), product, doc );
1334                }
1335    
1336                appendDerivedFrom( products[i].getDerivedFrom(), product, doc );
1337    
1338                element.appendChild( measures );
1339            }
1340    
1341        }
1342    
1343        private static void appendCarries( String[] asset, Element element, Document doc ) {
1344            if ( asset == null ) {
1345                return;
1346            }
1347    
1348            for ( int i = 0; i < asset.length; i++ ) {
1349                Element carries = doc.createElement( "sml:carries" );
1350                element.appendChild( carries );
1351                Element assetEle = doc.createElement( "sml:Asset" );
1352                carries.appendChild( assetEle );
1353                assetEle.appendChild( doc.createTextNode( asset[i] ) );
1354    
1355            }
1356    
1357        }
1358    }