001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/crs/configuration/deegree/CRSExporter.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.crs.configuration.deegree;
038    
039    import static org.deegree.crs.projections.ProjectionUtils.EPS11;
040    import static org.deegree.ogcbase.CommonNamespaces.CRSNS;
041    
042    import java.io.Writer;
043    import java.net.MalformedURLException;
044    import java.util.LinkedList;
045    import java.util.List;
046    import java.util.Properties;
047    
048    import javax.xml.transform.TransformerException;
049    
050    import org.deegree.crs.Identifiable;
051    import org.deegree.crs.components.Axis;
052    import org.deegree.crs.components.Ellipsoid;
053    import org.deegree.crs.components.GeodeticDatum;
054    import org.deegree.crs.components.PrimeMeridian;
055    import org.deegree.crs.components.Unit;
056    import org.deegree.crs.coordinatesystems.CompoundCRS;
057    import org.deegree.crs.coordinatesystems.CoordinateSystem;
058    import org.deegree.crs.coordinatesystems.GeocentricCRS;
059    import org.deegree.crs.coordinatesystems.GeographicCRS;
060    import org.deegree.crs.coordinatesystems.ProjectedCRS;
061    import org.deegree.crs.projections.Projection;
062    import org.deegree.crs.projections.azimuthal.StereographicAzimuthal;
063    import org.deegree.crs.projections.conic.LambertConformalConic;
064    import org.deegree.crs.projections.cylindric.TransverseMercator;
065    import org.deegree.crs.transformations.helmert.Helmert;
066    import org.deegree.crs.transformations.polynomial.PolynomialTransformation;
067    import org.deegree.datatypes.QualifiedName;
068    import org.deegree.framework.log.ILogger;
069    import org.deegree.framework.log.LoggerFactory;
070    import org.deegree.framework.xml.NamespaceContext;
071    import org.deegree.framework.xml.XMLFragment;
072    import org.deegree.framework.xml.XMLParsingException;
073    import org.deegree.framework.xml.XMLTools;
074    import org.deegree.ogcbase.CommonNamespaces;
075    import org.w3c.dom.Document;
076    import org.w3c.dom.Element;
077    
078    /**
079     * The <code>CRSExporter</code> exports to the old version format (no version attribute).
080     *
081     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
082     *
083     * @author last edited by: $Author: mschneider $
084     *
085     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
086     *
087     */
088    public class CRSExporter {
089    
090        private static ILogger LOG = LoggerFactory.getLogger( CRSExporter.class );
091    
092        /**
093         * The namespaces used in deegree.
094         */
095        private static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
096    
097        /**
098         * The prefix to use.
099         */
100        private final static String PRE = CommonNamespaces.CRS_PREFIX + ":";
101    
102        /**
103         *
104         * @param properties
105         *            to read configuration from.
106         */
107        public CRSExporter( Properties properties ) {
108            // nothing yet.
109        }
110    
111        /**
112         * Export the given list of CoordinateSystems into the crs-definition format.
113         *
114         * @param writer
115         * @param crsToExport
116         */
117        public void export( Writer writer, List<CoordinateSystem> crsToExport ) {
118            if ( crsToExport != null ) {
119                if ( crsToExport.size() != 0 ) {
120                    LOG.logDebug( "Trying to export: " + crsToExport.size() + " coordinate systems." );
121                    XMLFragment frag = new XMLFragment( new QualifiedName( "crs", "definitions", CommonNamespaces.CRSNS ) );
122                    Element root = frag.getRootElement();
123                    LinkedList<String> exportedIDs = new LinkedList<String>();
124                    for ( CoordinateSystem crs : crsToExport ) {
125                        if ( crs.getType() == CoordinateSystem.GEOCENTRIC_CRS ) {
126                            export( (GeocentricCRS) crs, root, exportedIDs );
127                        } else if ( crs.getType() == CoordinateSystem.GEOGRAPHIC_CRS ) {
128                            export( (GeographicCRS) crs, root, exportedIDs );
129                        } else if ( crs.getType() == CoordinateSystem.PROJECTED_CRS ) {
130                            export( (ProjectedCRS) crs, root, exportedIDs );
131                        } else if ( crs.getType() == CoordinateSystem.COMPOUND_CRS ) {
132                            export( (CompoundCRS) crs, root, exportedIDs );
133                        }
134                    }
135                    root.normalize();
136                    Document validDoc = createValidDocument( root );
137                    try {
138                        XMLFragment frag2 = new XMLFragment( validDoc, "http://www.deegree.org/crs" );
139                        frag2.prettyPrint( writer );
140                    } catch ( MalformedURLException e ) {
141                        LOG.logError( "Could not export crs definitions because: " + e.getMessage(), e );
142                    } catch ( TransformerException e ) {
143                        LOG.logError( "Could not export crs definitions because: " + e.getMessage(), e );
144                    }
145                } else {
146                    LOG.logWarning( "No coordinate system were given (list.size() == 0)." );
147                }
148            } else {
149                LOG.logError( "No coordinate system were given (list == null)." );
150            }
151        }
152    
153        /**
154         * Export the projected CRS to it's appropriate deegree-crs-definitions form.
155         *
156         * @param projectedCRS
157         *            to be exported
158         * @param rootNode
159         *            to export the projected CRS to.
160         * @param exportedIds
161         *            a list of id's already exported.
162         */
163        private void export( ProjectedCRS projectedCRS, Element rootNode, List<String> exportedIds ) {
164            if ( !exportedIds.contains( projectedCRS.getIdentifier() ) ) {
165                Element crsElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "projectedCRS" );
166                exportAbstractCRS( projectedCRS, crsElement );
167                GeographicCRS underLyingCRS = projectedCRS.getGeographicCRS();
168                export( underLyingCRS, rootNode, exportedIds );
169    
170                // Add a reference from the geographicCRS element to the projectedCRS element.
171                XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "usedGeographicCRS",
172                                        underLyingCRS.getIdentifier() );
173    
174                export( projectedCRS.getProjection(), crsElement );
175    
176                // Add the ids to the exportedID list.
177                for ( String eID : projectedCRS.getIdentifiers() ) {
178                    exportedIds.add( eID );
179                }
180                // finally add the crs node to the rootnode.
181                rootNode.appendChild( crsElement );
182            }
183        }
184    
185        /**
186         * Export the geocentric/geographic CRS to it's appropriate deegree-crs-definitions form.
187         *
188         * @param geographicCRS
189         *            to be exported
190         * @param rootNode
191         *            to export the geographic CRS to.
192         * @param exportedIds
193         *            a list of id's already exported.
194         */
195        private void export( GeographicCRS geographicCRS, Element rootNode, List<String> exportedIds ) {
196            if ( !exportedIds.contains( geographicCRS.getIdentifier() ) ) {
197                Element crsElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "geographicCRS" );
198                exportAbstractCRS( geographicCRS, crsElement );
199    
200                // export the datum.
201                GeodeticDatum datum = geographicCRS.getGeodeticDatum();
202                if ( datum != null ) {
203                    export( datum, rootNode, exportedIds );
204                    // Add a reference from the datum element to the geographic element.
205                    XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "usedDatum", datum.getIdentifier() );
206                } else {
207                    LOG.logError( "The given datum is not a geodetic one, this mey not be!" );
208                }
209                // Add the ids to the exportedID list.
210                for ( String eID : geographicCRS.getIdentifiers() ) {
211                    exportedIds.add( eID );
212                }
213                // finally add the crs node to the rootnode.
214                rootNode.appendChild( crsElement );
215            }
216        }
217    
218        /**
219         * Export the compoundCRS to it's appropriate deegree-crs-definitions form.
220         *
221         * @param compoundCRS
222         *            to be exported
223         * @param rootNode
224         *            to export the geographic CRS to.
225         * @param exportedIds
226         *            a list of id's already exported.
227         */
228        private void export( CompoundCRS compoundCRS, Element rootNode, List<String> exportedIds ) {
229            if ( !exportedIds.contains( compoundCRS.getIdentifier() ) ) {
230                Element crsElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "compoundCRS" );
231                exportIdentifiable( compoundCRS, crsElement );
232                CoordinateSystem underLyingCRS = compoundCRS.getUnderlyingCRS();
233                if ( underLyingCRS.getType() == CoordinateSystem.GEOGRAPHIC_CRS ) {
234                    export( (GeographicCRS) underLyingCRS, rootNode, exportedIds );
235                } else if ( underLyingCRS.getType() == CoordinateSystem.PROJECTED_CRS ) {
236                    export( (ProjectedCRS) underLyingCRS, rootNode, exportedIds );
237                }
238    
239                // Add a reference from the geographicCRS element to the projectedCRS element.
240                XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "usedCRS", underLyingCRS.getIdentifier() );
241                export( compoundCRS.getHeightAxis(), crsElement );
242    
243                XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "defaultHeight",
244                                        Double.toString( compoundCRS.getDefaultHeight() ) );
245    
246                // Add the ids to the exportedID list.
247                for ( String eID : compoundCRS.getIdentifiers() ) {
248                    exportedIds.add( eID );
249                }
250                // finally add the crs node to the rootnode.
251                rootNode.appendChild( crsElement );
252            }
253        }
254    
255        /**
256         * Export the projection to it's appropriate deegree-crs-definitions form.
257         *
258         * @param projection
259         *            to be exported
260         * @param rootNode
261         *            to export the projection to.
262         */
263        private void export( Projection projection, Element rootNode ) {
264            Element rootElem = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "projection" );
265            String elementName = projection.getImplementationName();
266            Element projectionElement = XMLTools.appendElement( rootElem, CommonNamespaces.CRSNS, PRE + elementName );
267            // exportIdentifiable( projection, projectionElement );
268            Element tmp = XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE
269                                                                                             + "latitudeOfNaturalOrigin",
270                                                  Double.toString( Math.toDegrees( projection.getProjectionLatitude() ) ) );
271            tmp.setAttribute( "inDegrees", "true" );
272            tmp = XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "longitudeOfNaturalOrigin",
273                                          Double.toString( Math.toDegrees( projection.getProjectionLongitude() ) ) );
274            tmp.setAttribute( "inDegrees", "true" );
275    
276            XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "scaleFactor",
277                                    Double.toString( projection.getScale() ) );
278            XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "falseEasting",
279                                    Double.toString( projection.getFalseEasting() ) );
280            XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "falseNorthing",
281                                    Double.toString( projection.getFalseNorthing() ) );
282            if ( "transverseMercator".equalsIgnoreCase( elementName ) ) {
283                XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "northernHemisphere",
284                                        Boolean.toString( ( (TransverseMercator) projection ).getHemisphere() ) );
285            } else if ( "lambertConformalConic".equalsIgnoreCase( elementName ) ) {
286                double paralellLatitude = ( (LambertConformalConic) projection ).getFirstParallelLatitude();
287                if ( !Double.isNaN( paralellLatitude ) && Math.abs( paralellLatitude ) > EPS11 ) {
288                    paralellLatitude = Math.toDegrees( paralellLatitude );
289                    tmp = XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS, PRE + "firstParallelLatitude",
290                                                  Double.toString( paralellLatitude ) );
291                    tmp.setAttribute( "inDegrees", "true" );
292                }
293                paralellLatitude = ( (LambertConformalConic) projection ).getSecondParallelLatitude();
294                if ( !Double.isNaN( paralellLatitude ) && Math.abs( paralellLatitude ) > EPS11 ) {
295                    paralellLatitude = Math.toDegrees( paralellLatitude );
296                    tmp = XMLTools.appendElement( projectionElement, CommonNamespaces.CRSNS,
297                                                  PRE + "secondParallelLatitude", Double.toString( paralellLatitude ) );
298                    tmp.setAttribute( "inDegrees", "true" );
299                }
300            } else if ( "stereographicAzimuthal".equalsIgnoreCase( elementName ) ) {
301                tmp = XMLTools.appendElement(
302                                              projectionElement,
303                                              CommonNamespaces.CRSNS,
304                                              PRE + "trueScaleLatitude",
305                                              Double.toString( ( (StereographicAzimuthal) projection ).getTrueScaleLatitude() ) );
306                tmp.setAttribute( "inDegrees", "true" );
307            }
308        }
309    
310        /**
311         * Export the confInvo to it's appropriate deegree-crs-definitions form.
312         *
313         * @param confInvo
314         *            to be exported
315         * @param rootNode
316         *            to export the confInvo to.
317         * @param exportedIds
318         *            a list of id's already exported.
319         */
320        private void export( Helmert confInvo, Element rootNode, final List<String> exportedIds ) {
321            if ( !exportedIds.contains( confInvo.getIdentifier() ) ) {
322                Element convElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "wgs84Transformation" );
323                exportIdentifiable( confInvo, convElement );
324    
325                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "xAxisTranslation",
326                                        Double.toString( confInvo.dx ) );
327                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "yAxisTranslation",
328                                        Double.toString( confInvo.dy ) );
329                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "zAxisTranslation",
330                                        Double.toString( confInvo.dz ) );
331                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "xAxisRotation",
332                                        Double.toString( confInvo.ex ) );
333                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "yAxisRotation",
334                                        Double.toString( confInvo.ey ) );
335                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "zAxisRotation",
336                                        Double.toString( confInvo.ez ) );
337                XMLTools.appendElement( convElement, CommonNamespaces.CRSNS, PRE + "scaleDifference",
338                                        Double.toString( confInvo.ppm ) );
339    
340                // Add the ids to the exportedID list.
341                for ( String eID : confInvo.getIdentifiers() ) {
342                    exportedIds.add( eID );
343                }
344    
345                // finally add the WGS84-Transformation node to the rootnode.
346                rootNode.appendChild( convElement );
347            }
348    
349        }
350    
351        /**
352         * Export the PrimeMeridian to it's appropriate deegree-crs-definitions form.
353         *
354         * @param pMeridian
355         *            to be exported
356         * @param rootNode
357         *            to export the pMeridian to.
358         * @param exportedIds
359         *            a list of id's already exported.
360         */
361        private void export( PrimeMeridian pMeridian, Element rootNode, final List<String> exportedIds ) {
362            if ( !exportedIds.contains( pMeridian.getIdentifier() ) ) {
363                Element meridianElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "primeMeridian" );
364                exportIdentifiable( pMeridian, meridianElement );
365                export( pMeridian.getAngularUnit(), meridianElement );
366                XMLTools.appendElement( meridianElement, CommonNamespaces.CRSNS, PRE + "longitude",
367                                        Double.toString( pMeridian.getLongitude() ) );
368    
369                // Add the ids to the exportedID list.
370                for ( String eID : pMeridian.getIdentifiers() ) {
371                    exportedIds.add( eID );
372                }
373    
374                // finally add the prime meridian node to the rootnode.
375                rootNode.appendChild( meridianElement );
376            }
377        }
378    
379        /**
380         * Export the ellipsoid to it's appropriate deegree-crs-definitions form.
381         *
382         * @param ellipsoid
383         *            to be exported
384         * @param rootNode
385         *            to export the ellipsoid to.
386         * @param exportedIds
387         *            a list of id's already exported.
388         */
389        private void export( Ellipsoid ellipsoid, Element rootNode, final List<String> exportedIds ) {
390            if ( !exportedIds.contains( ellipsoid.getIdentifier() ) ) {
391                Element ellipsoidElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "ellipsoid" );
392                exportIdentifiable( ellipsoid, ellipsoidElement );
393                XMLTools.appendElement( ellipsoidElement, CommonNamespaces.CRSNS, PRE + "semiMajorAxis",
394                                        Double.toString( ellipsoid.getSemiMajorAxis() ) );
395                XMLTools.appendElement( ellipsoidElement, CommonNamespaces.CRSNS, PRE + "inverseFlatting",
396                                        Double.toString( ellipsoid.getInverseFlattening() ) );
397                export( ellipsoid.getUnits(), ellipsoidElement );
398    
399                // Add the ids to the exportedID list.
400                for ( String eID : ellipsoid.getIdentifiers() ) {
401                    exportedIds.add( eID );
402                }
403                // finally add the ellipsoid node to the rootnode.
404                rootNode.appendChild( ellipsoidElement );
405            }
406        }
407    
408        /**
409         * Export the datum to it's appropriate deegree-crs-definitions form.
410         *
411         * @param datum
412         *            to be exported
413         * @param rootNode
414         *            to export the datum to.
415         * @param exportedIds
416         *            a list of id's already exported.
417         */
418        private void export( GeodeticDatum datum, Element rootNode, List<String> exportedIds ) {
419            if ( !exportedIds.contains( datum.getIdentifier() ) ) {
420                Element datumElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "geodeticDatum" );
421                exportIdentifiable( datum, datumElement );
422                /**
423                 * EXPORT the ELLIPSOID
424                 */
425                Ellipsoid ellipsoid = datum.getEllipsoid();
426                if ( ellipsoid != null ) {
427                    export( ellipsoid, rootNode, exportedIds );
428                    // Add a reference from the ellipsoid element to the datum element.
429                    XMLTools.appendElement( datumElement, CommonNamespaces.CRSNS, PRE + "usedEllipsoid",
430                                            ellipsoid.getIdentifier() );
431                }
432    
433                /**
434                 * EXPORT the PRIME_MERIDIAN
435                 */
436                PrimeMeridian pMeridian = datum.getPrimeMeridian();
437                if ( pMeridian != null ) {
438                    export( pMeridian, rootNode, exportedIds );
439                    // Add a reference from the prime meridian element to the datum element.
440                    XMLTools.appendElement( datumElement, CommonNamespaces.CRSNS, PRE + "usedPrimeMeridian",
441                                            pMeridian.getIdentifier() );
442                }
443    
444                /**
445                 * EXPORT the WGS-84-Conversion INFO
446                 */
447                Helmert confInvo = datum.getWGS84Conversion();
448                if ( confInvo != null ) {
449                    export( confInvo, rootNode, exportedIds );
450                    // Add a reference from the prime meridian element to the datum element.
451                    XMLTools.appendElement( datumElement, CommonNamespaces.CRSNS, PRE + "usedWGS84ConversionInfo",
452                                            confInvo.getIdentifier() );
453                }
454    
455                // Add the ids to the exportedID list.
456                for ( String eID : datum.getIdentifiers() ) {
457                    exportedIds.add( eID );
458                }
459                // finally add the datum node to the rootnode.
460                rootNode.appendChild( datumElement );
461            }
462        }
463    
464        /**
465         * Export toplevel crs features.
466         *
467         * @param crs
468         *            to be exported
469         * @param crsElement
470         *            to export to
471         */
472        private void exportAbstractCRS( CoordinateSystem crs, Element crsElement ) {
473            exportIdentifiable( crs, crsElement );
474            Axis[] axis = crs.getAxis();
475            StringBuilder axisOrder = new StringBuilder( 200 );
476            for ( int i = 0; i < axis.length; ++i ) {
477                Axis a = axis[i];
478                export( a, crsElement );
479                axisOrder.append( a.getName() );
480                if ( ( i + 1 ) < axis.length ) {
481                    axisOrder.append( ", " );
482                }
483            }
484            XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "axisOrder", axisOrder.toString() );
485    
486            export( crs.getTransformations(), crsElement );
487    
488        }
489    
490        /**
491         * Export the geocentric CRS to it's appropriate deegree-crs-definitions form.
492         *
493         * @param geocentricCRS
494         *            to be exported
495         * @param rootNode
496         *            to export the geocentric CRS to.
497         * @param exportedIds
498         *            a list of id's already exported.
499         */
500        private void export( GeocentricCRS geocentricCRS, Element rootNode, List<String> exportedIds ) {
501            if ( !exportedIds.contains( geocentricCRS.getIdentifier() ) ) {
502                Element crsElement = XMLTools.appendElement( rootNode, CommonNamespaces.CRSNS, PRE + "geocentricCRS" );
503                exportAbstractCRS( geocentricCRS, crsElement );
504                // export the datum.
505                GeodeticDatum datum = geocentricCRS.getGeodeticDatum();
506                if ( datum != null ) {
507                    export( datum, rootNode, exportedIds );
508                    // Add a reference from the datum element to the geocentric element.
509                    XMLTools.appendElement( crsElement, CommonNamespaces.CRSNS, PRE + "usedDatum", datum.getIdentifier() );
510                } // Add the ids to the exportedID list.
511                for ( String eID : geocentricCRS.getIdentifiers() ) {
512                    exportedIds.add( eID );
513                }
514                // finally add the crs node to the rootnode.
515                rootNode.appendChild( crsElement );
516            }
517        }
518    
519        /**
520         * Creates the basic nodes of the identifiable object.
521         *
522         * @param id
523         *            object to be exported.
524         * @param currentNode
525         *            to expand
526         */
527        private void exportIdentifiable( Identifiable id, Element currentNode ) {
528            for ( String i : id.getIdentifiers() ) {
529                if ( i != null ) {
530                    XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "id", i );
531                }
532    
533            }
534            if ( id.getNames() != null && id.getNames().length > 0 ) {
535                for ( String i : id.getNames() ) {
536                    if ( i != null ) {
537                        XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "name", i );
538                    }
539                }
540            }
541            if ( id.getVersions() != null && id.getVersions().length > 0 ) {
542                for ( String i : id.getVersions() ) {
543                    if ( i != null ) {
544                        XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "version", i );
545                    }
546                }
547            }
548            if ( id.getDescriptions() != null && id.getDescriptions().length > 0 ) {
549                for ( String i : id.getDescriptions() ) {
550                    if ( i != null ) {
551                        XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "description", i );
552                    }
553                }
554            }
555            if ( id.getAreasOfUse() != null && id.getAreasOfUse().length > 0 ) {
556                for ( String i : id.getAreasOfUse() ) {
557                    if ( i != null ) {
558                        XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "areaOfUse", i );
559                    }
560                }
561            }
562        }
563    
564        /**
565         * Export an axis to xml in the crs-definitions schema layout.
566         *
567         * @param axis
568         *            to be exported.
569         * @param currentNode
570         *            to export to.
571         */
572        private void export( Axis axis, Element currentNode ) {
573            Document doc = currentNode.getOwnerDocument();
574            Element axisElement = doc.createElementNS( CRSNS.toASCIIString(), PRE + "Axis" );
575            // The name.
576            XMLTools.appendElement( axisElement, CommonNamespaces.CRSNS, PRE + "name", axis.getName() );
577    
578            // the units.
579            Unit units = axis.getUnits();
580            export( units, axisElement );
581    
582            XMLTools.appendElement( axisElement, CommonNamespaces.CRSNS, PRE + "axisOrientation",
583                                    axis.getOrientationAsString() );
584            currentNode.appendChild( axisElement );
585        }
586    
587        /**
588         * Export a list of transformations to the crs element to xml with respect to the crs-definitions schema layout.
589         *
590         * @param transformations
591         *            to be exported.
592         * @param currentNode
593         *            to export to.
594         */
595        private void export( List<PolynomialTransformation> transformations, Element currentNode ) {
596            for ( PolynomialTransformation transformation : transformations ) {
597                Element transformationElement = XMLTools.appendElement( currentNode, CRSNS, PRE
598                                                                                            + "polynomialTransformation" );
599                if ( !"leastsquare".equals( transformation.getImplementationName().toLowerCase() ) ) {
600                    transformationElement.setAttribute( "class", transformation.getClass().getCanonicalName() );
601                }
602                Element transformElement = XMLTools.appendElement( transformationElement, CRSNS,
603                                                                   PRE + transformation.getImplementationName() );
604                XMLTools.appendElement( transformElement, CRSNS, PRE + "polynomialOrder",
605                                        Integer.toString( transformation.getOrder() ) );
606                XMLTools.appendElement( transformElement, CRSNS, PRE + "xParameters",
607                                        transformation.getFirstParams().toString() );
608                XMLTools.appendElement( transformElement, CRSNS, PRE + "yParameters",
609                                        transformation.getSecondParams().toString() );
610                XMLTools.appendElement( transformElement, CRSNS, PRE + "targetCRS",
611                                        transformation.getTargetCRS().getIdentifier() );
612            }
613        }
614    
615        /**
616         * Export a unit to xml in the crs-definitions schema layout.
617         *
618         * @param units
619         *            to be exported.
620         * @param currentNode
621         *            to export to.
622         */
623        private void export( Unit units, Element currentNode ) {
624            if ( units != null && currentNode != null ) {
625                XMLTools.appendElement( currentNode, CommonNamespaces.CRSNS, PRE + "units", units.getName() );
626            }
627        }
628    
629        private Document createValidDocument( Element root ) {
630            // List<Element> lastInput = new LinkedList<Element>( 100 );
631            try {
632                List<Element> valid = XMLTools.getElements( root, PRE + "ellipsoid", nsContext );
633                valid.addAll( XMLTools.getElements( root, PRE + "geodeticDatum", nsContext ) );
634                valid.addAll( XMLTools.getElements( root, PRE + "projectedCRS", nsContext ) );
635                valid.addAll( XMLTools.getElements( root, PRE + "geographicCRS", nsContext ) );
636                valid.addAll( XMLTools.getElements( root, PRE + "compoundCRS", nsContext ) );
637                valid.addAll( XMLTools.getElements( root, PRE + "geocentricCRS", nsContext ) );
638                valid.addAll( XMLTools.getElements( root, PRE + "primeMeridian", nsContext ) );
639                valid.addAll( XMLTools.getElements( root, PRE + "wgs84Transformation", nsContext ) );
640                Document doc = XMLTools.create();
641                Element newRoot = doc.createElementNS( CommonNamespaces.CRSNS.toASCIIString(), PRE + "definitions" );
642                newRoot = (Element) doc.importNode( newRoot, false );
643                newRoot = (Element) doc.appendChild( newRoot );
644                for ( int i = 0; i < valid.size(); ++i ) {
645                    Element el = valid.get( i );
646                    el = (Element) doc.importNode( el, true );
647                    newRoot.appendChild( el );
648                }
649                XMLTools.appendNSBinding( newRoot, CommonNamespaces.XSI_PREFIX, CommonNamespaces.XSINS );
650                newRoot.setAttributeNS(
651                                        CommonNamespaces.XSINS.toASCIIString(),
652                                        "xsi:schemaLocation",
653                                        "http://www.deegree.org/crs c:/windows/profiles/rutger/EIGE~VO5/eclipse-projekte/coordinate_systems/resources/schema/crsdefinition.xsd" );
654                return doc;
655            } catch ( XMLParsingException xmle ) {
656                xmle.printStackTrace();
657            }
658            return root.getOwnerDocument();
659        }
660    
661    }