001    // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcbase/XMLFactory.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.ogcbase;
037    
038    import java.io.ByteArrayInputStream;
039    import java.net.URI;
040    
041    import org.deegree.datatypes.CodeList;
042    import org.deegree.datatypes.time.TimeDuration;
043    import org.deegree.datatypes.time.TimePeriod;
044    import org.deegree.datatypes.time.TimePosition;
045    import org.deegree.datatypes.time.TimeSequence;
046    import org.deegree.datatypes.values.Interval;
047    import org.deegree.datatypes.values.TypedLiteral;
048    import org.deegree.datatypes.values.Values;
049    import org.deegree.datatypes.xlink.SimpleLink;
050    import org.deegree.framework.log.ILogger;
051    import org.deegree.framework.log.LoggerFactory;
052    import org.deegree.framework.util.StringTools;
053    import org.deegree.framework.util.TimeTools;
054    import org.deegree.framework.xml.XMLFragment;
055    import org.deegree.framework.xml.XMLTools;
056    import org.deegree.model.crs.CoordinateSystem;
057    import org.deegree.model.metadata.iso19115.Keywords;
058    import org.deegree.model.metadata.iso19115.OnlineResource;
059    import org.deegree.model.spatialschema.Envelope;
060    import org.deegree.model.spatialschema.GMLGeometryAdapter;
061    import org.deegree.model.spatialschema.Geometry;
062    import org.deegree.model.spatialschema.GeometryException;
063    import org.deegree.ogcwebservices.LonLatEnvelope;
064    import org.w3c.dom.Element;
065    import org.w3c.dom.Node;
066    import org.w3c.dom.Text;
067    
068    /**
069     * Factory for creating <code>DOM</code> representations from java objects used to represent OGC
070     * related schema types.
071     *
072     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
073     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
074     * @author last edited by: $Author: mschneider $
075     *
076     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
077     */
078    public class XMLFactory {
079    
080        protected static final ILogger LOG = LoggerFactory.getLogger( XMLFactory.class );
081    
082        protected static final URI OGCNS = CommonNamespaces.OGCNS;
083    
084        protected static final URI GMLNS = CommonNamespaces.GMLNS;
085    
086        protected static final URI XLNNS = CommonNamespaces.XLNNS;
087    
088        /**
089         * Appends the <code>DOM</code> representation of a <code>LonLatEnvelope</code> to the
090         * passed <code>Element</code>.
091         *
092         * @param root
093         * @param lonLatEnvelope
094         * @param namespaceURI
095         */
096        protected static void appendLonLatEnvelope( Element root, LonLatEnvelope lonLatEnvelope, URI namespaceURI ) {
097            Element lonLatEnvelopeElement = XMLTools.appendElement( root, namespaceURI, "lonLatEnvelope" );
098            //lonLatEnvelopeElement.setAttribute( "srsName", "WGS84(DD)" );
099            lonLatEnvelopeElement.setAttribute( "srsName", lonLatEnvelope.getSrs() );
100            String min = lonLatEnvelope.getMin().getX() + " " + lonLatEnvelope.getMin().getY();
101            Element elem = XMLTools.appendElement( lonLatEnvelopeElement, GMLNS, "gml:pos", min );
102            elem.setAttribute( "dimension", "2" );
103            String max = lonLatEnvelope.getMax().getX() + " " + lonLatEnvelope.getMax().getY();
104            elem = XMLTools.appendElement( lonLatEnvelopeElement, GMLNS, "gml:pos", max );
105            elem.setAttribute( "dimension", "2" );
106            TimePosition[] tpos = lonLatEnvelope.getTimePositions();
107            if ( tpos != null ) {
108                for ( int i = 0; i < tpos.length; i++ ) {
109                    appendTimePosition( lonLatEnvelopeElement, tpos[i] );
110                }
111            }
112        }
113    
114        /**
115         * Appends an <code>XML/GML Envelope</code> -element to the passed <code>Element</code>.
116         *
117         * @param xmlNode
118         * @param envelope
119         */
120        protected static void appendEnvelope( Element xmlNode, Envelope envelope ) {
121            Element node = XMLTools.appendElement( xmlNode, GMLNS, "gml:Envelope" );
122            CoordinateSystem crs = envelope.getCoordinateSystem();
123            if ( crs != null ) {
124                try {
125                    node.setAttribute( "srsName", crs.getIdentifier() );
126                } catch ( Exception e ) {
127                    e.printStackTrace();
128                }
129            }
130            Element env = node;
131    
132            String min = envelope.getMin().getX() + " " + envelope.getMin().getY();
133            node = XMLTools.appendElement( env, GMLNS, "gml:pos", min );
134            node.setAttribute( "dimension", "2" );
135    
136            String max = envelope.getMax().getX() + " " + envelope.getMax().getY();
137            node = XMLTools.appendElement( env, GMLNS, "gml:pos", max );
138            node.setAttribute( "dimension", "2" );
139        }
140    
141        /**
142         * Appends the <code>XML/GML</code> representation of a <code>TimePosition</code> to the
143         * passed <code>Element</code>.
144         *
145         * @param xmlNode
146         * @param tpos
147         */
148        protected static void appendTimePosition( Element xmlNode, TimePosition tpos ) {
149            if ( tpos != null ) {
150                String s = TimeTools.getISOFormattedTime( tpos.getTime() );
151                Element element = XMLTools.appendElement( xmlNode, GMLNS, "gml:timePosition", s );
152                element.setAttribute( "calendarEraName", tpos.getCalendarEraName() );
153                element.setAttribute( "frame", tpos.getFrame().toString() );
154                element.setAttribute( "indeterminatePosition", tpos.getIndeterminatePosition().value );
155            }
156        }
157    
158        /**
159         * Appends a <code>keywords</code> -element for each <code>Keywords</code> object of the
160         * passed array to the passed <code>Element</code>.
161         *
162         * @param xmlNode
163         * @param keywords
164         * @param namespaceURI
165         */
166        protected static void appendKeywords( Element xmlNode, Keywords[] keywords, URI namespaceURI ) {
167            if ( keywords != null ) {
168                for ( int i = 0; i < keywords.length; i++ ) {
169                    Element node = XMLTools.appendElement( xmlNode, namespaceURI, "keywords" );
170                    appendKeywords( node, keywords[i], namespaceURI );
171                }
172            }
173        }
174    
175        /**
176         * Appends a <code>keywords</code> -element to the passed <code>Element</code> and fills it
177         * with the available keywords.
178         *
179         * @param xmlNode
180         * @param keywords
181         * @param namespaceURI
182         */
183        protected static void appendKeywords( Element xmlNode, Keywords keywords, URI namespaceURI ) {
184            if ( keywords != null ) {
185                String[] kw = keywords.getKeywords();
186                for ( int i = 0; i < kw.length; i++ ) {
187                    XMLTools.appendElement( xmlNode, namespaceURI, "keyword", kw[i] );
188                }
189                if ( keywords.getThesaurusName() != null ) {
190                    XMLTools.appendElement( xmlNode, namespaceURI, "type", keywords.getThesaurusName() );
191                }
192            }
193        }
194    
195        /**
196         * Appends an <code>XML</code> representation of the passed <code>TimeSequence</code> to the
197         * passed <code>Element</code>.
198         *
199         * @param xmlNode
200         * @param timeSeq
201         * @param namespaceURI
202         */
203        protected static void appendTemporalDomain( Element xmlNode, TimeSequence timeSeq, URI namespaceURI ) {
204            if ( timeSeq != null ) {
205                Element node = XMLTools.appendElement( xmlNode, namespaceURI, "temporalDomain", null );
206                TimePeriod[] tPer = timeSeq.getTimePeriod();
207                if ( tPer != null ) {
208                    for ( int i = 0; i < tPer.length; i++ ) {
209                        appendTimePeriod( node, tPer[i], namespaceURI );
210                    }
211                }
212    
213                TimePosition[] tPos = timeSeq.getTimePosition();
214                if ( tPos != null ) {
215                    for ( int i = 0; i < tPos.length; i++ ) {
216                        appendTimePosition( node, tPos[i] );
217                    }
218                }
219            }
220        }
221    
222        /**
223         * Appends an <code>XML</code> representation of the passed <code>TimePeriod</code> to the
224         * passed <code>Element</code>.
225         *
226         * @param xmlNode
227         * @param tPeriod
228         * @param namespaceURI
229         */
230        protected static void appendTimePeriod( Element xmlNode, TimePeriod tPeriod, URI namespaceURI ) {
231            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "timePeriod" );
232            appendTimePosition( node, tPeriod.getBeginPosition() );
233            appendTimePosition( node, tPeriod.getEndPosition() );
234            appendTimeResolution( node, tPeriod.getTimeResolution() );
235        }
236    
237        /**
238         * Appends an <code>XML/GML</code> representation of the passed <code>TimeDuration</code> to
239         * the passed <code>Element</code>.
240         *
241         * @param xmlNode
242         * @param duration
243         */
244        protected static void appendTimeResolution( Element xmlNode, TimeDuration duration ) {
245            XMLTools.appendElement( xmlNode, GMLNS, "gml:timeResolution", duration.getAsGMLTimeDuration() );
246        }
247    
248        /**
249         * Appends an <code>XML</code> representation of the passed <code>Values</code> to the
250         * passed <code>Element</code>.
251         *
252         * @param xmlNode
253         * @param values
254         * @param namespaceURI
255         */
256        protected static void appendValues( Element xmlNode, Values values, URI namespaceURI ) {
257            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "values" );
258            if ( values.getType() != null ) {
259                node.setAttribute( "type", values.getType().toString() );
260            }
261            if ( values.getSemantic() != null ) {
262                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
263                node.setAttributeNS( namespaceURI.toString(), "dgr:semantic", values.getSemantic().toString() );
264            }
265            Interval[] intervals = values.getInterval();
266            if ( intervals != null ) {
267                for ( int i = 0; i < intervals.length; i++ ) {
268                    appendInterval( node, intervals[i], namespaceURI );
269                }
270            }
271            TypedLiteral[] sVal = values.getSingleValue();
272            if ( sVal != null ) {
273                for ( int i = 0; i < sVal.length; i++ ) {
274                    appendTypedLiteral( node, sVal[i], "singleValue", namespaceURI );
275                }
276            }
277        }
278    
279        /**
280         * Appends an <code>XML</code> representation of the passed <code>Interval</code> to the
281         * passed <code>Element</code>.
282         *
283         * @param xmlNode
284         * @param interval
285         * @param namespaceURI
286         */
287        protected static void appendInterval( Element xmlNode, Interval interval, URI namespaceURI ) {
288            Element node = XMLTools.appendElement( xmlNode, namespaceURI, "interval" );
289            Element inter = node;
290            if ( interval.getType() != null ) {
291                node.setAttribute( "type", interval.getType().toString() );
292            }
293    
294            if ( interval.getSemantic() != null ) {
295                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
296                node.setAttributeNS( namespaceURI.toString(), "dgr:semantic", interval.getSemantic().toString() );
297            }
298            node.setAttribute( "atomic", "" + interval.isAtomic() );
299            if ( interval.getClosure() != null && interval.getClosure().value != "" && interval.getClosure().value != null ) {
300                node.setAttribute( "xmlns:dgr", namespaceURI.toString() );
301                node.setAttributeNS( namespaceURI.toString(), "dgr:closure", interval.getClosure().value );
302            }
303            node = XMLTools.appendElement( inter, namespaceURI, "min", interval.getMin().getValue() );
304            if ( interval.getMin().getType() != null ) {
305                node.setAttribute( "type", interval.getMin().getType().toString() );
306            }
307            node = XMLTools.appendElement( inter, namespaceURI, "max", interval.getMin().getValue() );
308            if ( interval.getMax().getType() != null ) {
309                node.setAttribute( "type", interval.getMax().getType().toString() );
310            }
311            node = XMLTools.appendElement( inter, namespaceURI, "res", interval.getRes().getValue() );
312            if ( interval.getRes().getType() != null ) {
313                node.setAttribute( "type", interval.getRes().getType().toString() );
314            }
315        }
316    
317        /**
318         * Appends an <code>XML</code> representation of the passed <code>TypedLiteral</code> to the
319         * passed <code>Element</code>.
320         *
321         * @param xmlNode
322         * @param singleValue
323         * @param name
324         * @param namespaceURI
325         */
326        protected static void appendTypedLiteral( Element xmlNode, TypedLiteral singleValue, String name, URI namespaceURI ) {
327            Node node = XMLTools.appendElement( xmlNode, namespaceURI, name, singleValue.getValue() );
328            if ( singleValue.getType() != null ) {
329                ( (Element) node ).setAttribute( "type", singleValue.getType().toString() );
330            }
331        }
332    
333        /**
334         * Appends an <code>XML</code> representation of the passed <code>CodeList</code> to the
335         * passed <code>Element</code>.
336         *
337         * @param xmlNode
338         * @param codeList
339         * @param namespaceURI
340         */
341        protected static void appendCodeList( Element xmlNode, CodeList codeList, URI namespaceURI ) {
342            String[] codes = codeList.getCodes();
343            String s = StringTools.arrayToString( codes, ' ' );
344            Node node = XMLTools.appendElement( xmlNode, namespaceURI, codeList.getName(), s );
345            if ( codeList.getCodeSpace() != null ) {
346                ( (Element) node ).setAttribute( "codeSpace", codeList.getCodeSpace().toString() );
347            }
348        }
349    
350        /**
351         * Appends the XML attributes of the given <code>SimpleLink</code> to the also passed
352         * <code>Element</code>.
353         *
354         * @param linkElement
355         * @param simpleLink
356         */
357        protected static void appendSimpleLinkAttributes( Element linkElement, SimpleLink simpleLink ) {
358    
359            linkElement.setAttributeNS( XLNNS.toString(), "xlink:type", "simple" );
360            if ( simpleLink.getHref() != null ) {
361                linkElement.setAttributeNS( XLNNS.toString(), "xlink:href", simpleLink.getHref().toString() );
362            }
363            if ( simpleLink.getRole() != null ) {
364                linkElement.setAttributeNS( XLNNS.toString(), "xlink:role", simpleLink.getRole().toString() );
365            }
366            if ( simpleLink.getArcrole() != null ) {
367                linkElement.setAttributeNS( XLNNS.toString(), "xlink:arcrole", simpleLink.getArcrole().toString() );
368            }
369            if ( simpleLink.getTitle() != null ) {
370                linkElement.setAttributeNS( XLNNS.toString(), "xlink:title", simpleLink.getTitle() );
371            }
372            if ( simpleLink.getShow() != null ) {
373                linkElement.setAttributeNS( XLNNS.toString(), "xlink:show", simpleLink.getShow() );
374            }
375            if ( simpleLink.getActuate() != null ) {
376                linkElement.setAttributeNS( XLNNS.toString(), "xlink:actuate", simpleLink.getActuate() );
377            }
378        }
379    
380        /**
381         * Appends the <code>DOM</code> representation of a simple <code>XLink</code> -element to
382         * the passed <code>Element</code>.
383         *
384         * @param xmlNode
385         * @param elementName
386         * @param onlineResource
387         * @param namespaceURI
388         */
389        protected static void appendOnlineResource( Element xmlNode, String elementName, OnlineResource onlineResource,
390                                                    URI namespaceURI ) {
391            Element linkElement = XMLTools.appendElement( xmlNode, namespaceURI, elementName );
392            linkElement.setAttributeNS( XLNNS.toString(), "xlink:type", "simple" );
393            linkElement.setAttributeNS( XLNNS.toString(), "xlink:href", onlineResource.getLinkage().getHref().toString() );
394        }
395    
396        /**
397         * Appends the <code>DOM</code> representation of the given <code>PropertyPath</code> as a
398         * new text node to the given element (including necessary namespace bindings).
399         *
400         * @param element
401         *            Element node where the PropertyPath is appended to
402         * @param propertyPath
403         */
404        protected static void appendPropertyPath( Element element, PropertyPath propertyPath ) {
405            StringBuffer sb = new StringBuffer();
406            sb.append( propertyPath );
407    
408            Text textNode = element.getOwnerDocument().createTextNode( sb.toString() );
409            element.appendChild( textNode );
410            XMLTools.appendNSBindings( element, propertyPath.getNamespaceContext() );
411        }
412    
413        /**
414         * Appends the <code>DOM</code> representation of the given feature id to the given element.
415         *
416         * @param root
417         *            Element node where the "ogc:FeatureId" element is appended to
418         * @param fid
419         *            feature identifier
420         */
421        protected static void appendFeatureId( Element root, String fid ) {
422            Element gmlObjectIdElement = XMLTools.appendElement( root, OGCNS, "ogc:FeatureId" );
423            gmlObjectIdElement.setAttribute( "fid", fid );
424        }
425    
426        /**
427         * Appends the <code>DOM</code> representation of the given {@link Geometry} to the given
428         * element.
429         *
430         * TODO Do this a better way...
431         *
432         * @param el
433         *            element node where the geometry is appended to
434         * @param geom
435         *            geometry to be appended
436         * @throws GeometryException
437         */
438        protected static void appendGeometry( Element el, Geometry geom )
439                                throws GeometryException {
440    
441            StringBuffer sb = new StringBuffer();
442            sb.append( "<dummy xmlns:gml=\"" );
443            sb.append( CommonNamespaces.GMLNS.toString() );
444            sb.append( "\">" );
445            sb.append( GMLGeometryAdapter.export( geom ) );
446            sb.append( "</dummy>" );
447    
448            ByteArrayInputStream bis = new ByteArrayInputStream( sb.toString().getBytes() );
449            try {
450                GMLDocument doc = new GMLDocument();
451                doc.load( bis, XMLFragment.DEFAULT_URL );
452                XMLTools.insertNodeInto( XMLTools.getFirstChildElement( doc.getRootElement() ), el );
453            } catch ( Exception e ) {
454                throw new GeometryException( e.getMessage() );
455            }
456        }
457    }