001    // $HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/framework/xml/XMLFragment.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.framework.xml;
038    
039    import java.io.File;
040    import java.io.IOException;
041    import java.io.InputStream;
042    import java.io.InputStreamReader;
043    import java.io.OutputStream;
044    import java.io.PushbackInputStream;
045    import java.io.PushbackReader;
046    import java.io.Reader;
047    import java.io.Serializable;
048    import java.io.StringWriter;
049    import java.io.Writer;
050    import java.net.MalformedURLException;
051    import java.net.URI;
052    import java.net.URISyntaxException;
053    import java.net.URL;
054    import java.util.HashMap;
055    import java.util.LinkedList;
056    import java.util.Map;
057    import java.util.NoSuchElementException;
058    import java.util.Properties;
059    import java.util.StringTokenizer;
060    
061    import javax.xml.parsers.DocumentBuilder;
062    import javax.xml.parsers.DocumentBuilderFactory;
063    import javax.xml.parsers.ParserConfigurationException;
064    import javax.xml.transform.OutputKeys;
065    import javax.xml.transform.Source;
066    import javax.xml.transform.Transformer;
067    import javax.xml.transform.TransformerConfigurationException;
068    import javax.xml.transform.TransformerException;
069    import javax.xml.transform.TransformerFactory;
070    import javax.xml.transform.dom.DOMSource;
071    import javax.xml.transform.stream.StreamResult;
072    import javax.xml.transform.stream.StreamSource;
073    
074    import org.deegree.datatypes.QualifiedName;
075    import org.deegree.datatypes.xlink.SimpleLink;
076    import org.deegree.framework.log.ILogger;
077    import org.deegree.framework.log.LoggerFactory;
078    import org.deegree.framework.util.BootLogger;
079    import org.deegree.framework.util.CharsetUtils;
080    import org.deegree.framework.util.FileUtils;
081    import org.deegree.framework.util.StringTools;
082    import org.deegree.model.feature.Messages;
083    import org.deegree.ogcbase.CommonNamespaces;
084    import org.w3c.dom.Document;
085    import org.w3c.dom.Element;
086    import org.w3c.dom.NamedNodeMap;
087    import org.w3c.dom.Node;
088    import org.xml.sax.InputSource;
089    import org.xml.sax.SAXException;
090    
091    /**
092     * An instance of <code>XMLFragment</code> encapsulates an underlying {@link Element} which acts as the root element of
093     * the document (which may be a fragment or a whole document).
094     * <p>
095     * Basically, <code>XMLFragment</code> provides easy loading and proper saving (automatically generated CDATA-elements
096     * for text nodes that need to be escaped) and acts as base class for all XML parsers in deegree.
097     *
098     * TODO: automatically generated CDATA-elements are not implemented yet
099     *
100     * <p>
101     * Additionally, <code>XMLFragment</code> tries to make the handling of relative paths inside the document's content as
102     * painless as possible. This means that after initialization of the <code>XMLFragment</code> with the correct SystemID
103     * (i.e. the URL of the document):
104     * <ul>
105     * <li>external parsed entities (in the DOCTYPE part) can use relative URLs; e.g. &lt;!ENTITY local SYSTEM
106     * "conf/wfs/wfs.cfg"&gt;</li>
107     * <li>application specific documents which extend <code>XMLFragment</code> can resolve relative URLs during parsing by
108     * calling the <code>resolve()</code> method</li>
109     * </ul>
110     *
111     * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </a>
112     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a>
113     * @author last edited by: $Author: mschneider $
114     *
115     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
116     *
117     * @see org.deegree.framework.xml.XMLTools
118     */
119    
120    public class XMLFragment implements Serializable {
121    
122        private static final long serialVersionUID = 8984447437613709386L;
123    
124        /**
125         * The namespace map containing the prefixes mapped to the namespaces.
126         */
127        protected static NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
128    
129        /**
130         * The xlink namespace
131         */
132        protected static final URI XLNNS = CommonNamespaces.XLNNS;
133    
134        private static final ILogger LOG = LoggerFactory.getLogger( XMLFragment.class );
135    
136        /**
137         * Use this URL as SystemID only if an <code>XMLFragment</code> cannot be pinpointed to a URL - in this case it may
138         * not use any relative references!
139         */
140        public static final String DEFAULT_URL = "http://www.deegree.org";
141    
142        private URL systemId;
143    
144        private Element rootElement;
145    
146        static {
147            LOG.logDebug( "DOM implementation in use (DocumentBuilderFactory): "
148                          + DocumentBuilderFactory.newInstance().getClass().getName() );
149            try {
150                LOG.logDebug( "DOM implementation in use (DocumentBuilder): "
151                              + DocumentBuilderFactory.newInstance().newDocumentBuilder().getClass().getName() );
152            } catch ( Exception e ) {
153                BootLogger.logError( "Error creating test DocumentBuilder instance.", e );
154            }
155        }
156    
157        /**
158         * Creates a new <code>XMLFragment</code> which is not initialized.
159         */
160        public XMLFragment() {
161            // nothing to do
162        }
163    
164        /**
165         * Creates a new <code>XMLFragment</code> which is loaded from the given <code>URL</code>.
166         *
167         * @param url
168         * @throws IOException
169         * @throws SAXException
170         */
171        public XMLFragment( URL url ) throws IOException, SAXException {
172            load( url );
173        }
174    
175        /**
176         * Creates a new <code>XMLFragment</code> which is loaded from the given <code>File</code>.
177         *
178         * @param file
179         *            the file to load from
180         * @throws SAXException
181         *             if the document could not be parsed
182         * @throws IOException
183         *             if the document could not be read
184         * @throws MalformedURLException
185         *             if the file cannot be transposed to a valid url
186         */
187        public XMLFragment( File file ) throws MalformedURLException, IOException, SAXException {
188            if ( file != null ) {
189                load( file.toURI().toURL() );
190            }
191        }
192    
193        /**
194         * Creates a new <code>XMLFragment</code> which is loaded from the given <code>Reader</code>.
195         *
196         * @param reader
197         * @param systemId
198         *            this string should represent a URL that is related to the passed reader. If this URL is not available
199         *            or unknown, the string should contain the value of XMLFragment.DEFAULT_URL
200         * @throws SAXException
201         * @throws IOException
202         */
203        public XMLFragment( Reader reader, String systemId ) throws SAXException, IOException {
204            load( reader, systemId );
205        }
206    
207        /**
208         * Creates a new <code>XMLFragment</code> instance based on the submitted <code>Document</code>.
209         *
210         * @param doc
211         * @param systemId
212         *            this string should represent a URL that is the source of the passed doc. If this URL is not available
213         *            or unknown, the string should contain the value of XMLFragment.DEFAULT_URL
214         * @throws MalformedURLException
215         *             if systemId is no valid and absolute <code>URL</code>
216         */
217        public XMLFragment( Document doc, String systemId ) throws MalformedURLException {
218            setRootElement( doc.getDocumentElement() );
219            setSystemId( systemId );
220        }
221    
222        /**
223         * Creates a new <code>XMLFragment</code> instance based on the submitted <code>Element</code>.
224         *
225         * @param element
226         */
227        public XMLFragment( Element element ) {
228            setRootElement( element );
229        }
230    
231        /**
232         * Constructs an empty document with the given <code>QualifiedName</code> as root node.
233         *
234         * @param elementName
235         *            if the name's namespace is set, the prefix should be set as well.
236         */
237        public XMLFragment( QualifiedName elementName ) {
238            try {
239                DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
240                if ( elementName.getNamespace() == null ) {
241                    rootElement = db.newDocument().createElement( elementName.getLocalName() );
242                } else {
243                    String pre = elementName.getPrefix();
244                    String ns = elementName.getNamespace().toString();
245                    if ( pre == null || pre.trim().length() == 0 ) {
246                        pre = "dummy";
247                        LOG.logWarning( StringTools.concat( 200, "Incorrect usage of deegree API,",
248                                                            " prefix of a root node was not ", "defined:\nNode name was ",
249                                                            elementName.getLocalName(), ", namespace was ", ns ) );
250                    }
251                    String name = StringTools.concat( 200, pre, ":", elementName.getLocalName() );
252                    rootElement = db.newDocument().createElementNS( ns, name );
253                    rootElement.getOwnerDocument().appendChild( rootElement );
254                }
255            } catch ( ParserConfigurationException e ) {
256                LOG.logError( "The parser seems to be misconfigured. Broken installation?", e );
257            }
258        }
259    
260        /**
261         * Returns the systemId (the URL of the <code>XMLFragment</code>).
262         *
263         * @return the systemId
264         */
265        public URL getSystemId() {
266            return systemId;
267        }
268    
269        /**
270         * @param systemId
271         *            The systemId (physical location) to set (may be null).
272         * @throws MalformedURLException
273         */
274        public void setSystemId( String systemId )
275                                throws MalformedURLException {
276            if ( systemId != null ) {
277                this.systemId = new URL( systemId );
278            }
279        }
280    
281        /**
282         * @param systemId
283         *            The systemId (physical location) to set.
284         */
285        public void setSystemId( URL systemId ) {
286            this.systemId = systemId;
287        }
288    
289        /**
290         * Returns whether the document has a schema reference.
291         *
292         * @return true, if the document has a schema reference, false otherwise
293         */
294        public boolean hasSchema() {
295            if ( this.rootElement.getAttribute( "xsi:schemaLocation" ) != null ) {
296                return true;
297            }
298            return false;
299        }
300    
301        /**
302         * Determines the namespace <code>URI</code>s and the bound schema <code>URL</code>s from the 'xsi:schemaLocation'
303         * attribute of the document element.
304         *
305         * @return keys are URIs (namespaces), values are URLs (schema locations)
306         * @throws XMLParsingException
307         */
308        public Map<URI, URL> getAttachedSchemas()
309                                throws XMLParsingException {
310    
311            Map<URI, URL> schemaMap = new HashMap<URI, URL>();
312    
313            NamedNodeMap attrMap = rootElement.getAttributes();
314            Node schemaLocationAttr = attrMap.getNamedItem( "xsi:schemaLocation" );
315            if ( schemaLocationAttr == null ) {
316                return schemaMap;
317            }
318    
319            String target = schemaLocationAttr.getNodeValue();
320            StringTokenizer tokenizer = new StringTokenizer( target );
321    
322            while ( tokenizer.hasMoreTokens() ) {
323                URI nsURI = null;
324                String token = tokenizer.nextToken();
325                try {
326                    nsURI = new URI( token );
327                } catch ( URISyntaxException e ) {
328                    String msg = "Invalid 'xsi:schemaLocation' attribute: namespace " + token + "' is not a valid URI.";
329                    LOG.logError( msg );
330                    throw new XMLParsingException( msg );
331                }
332    
333                URL schemaURL = null;
334                try {
335                    token = tokenizer.nextToken();
336                    schemaURL = resolve( token );
337                } catch ( NoSuchElementException e ) {
338                    String msg = "Invalid 'xsi:schemaLocation' attribute: namespace '" + nsURI
339                                 + "' is missing a schema URL.";
340                    LOG.logError( msg );
341                    throw new XMLParsingException( msg );
342                } catch ( MalformedURLException ex ) {
343                    String msg = "Invalid 'xsi:schemaLocation' attribute: '" + token + "' for namespace '" + nsURI
344                                 + "' could not be parsed as URL.";
345                    throw new XMLParsingException( msg );
346                }
347                schemaMap.put( nsURI, schemaURL );
348            }
349            return schemaMap;
350        }
351    
352        /**
353         * Initializes the <code>XMLFragment</code> with the content from the given <code>URL</code>. Sets the SystemId,
354         * too.
355         *
356         * @param url
357         * @throws IOException
358         * @throws SAXException
359         */
360        public void load( URL url )
361                                throws IOException, SAXException {
362            if ( url == null ) {
363                throw new IllegalArgumentException( "The given url may not be null" );
364            }
365    
366            String uri = url.toExternalForm();
367            load( url.openStream(), uri );
368        }
369    
370        /**
371         * Initializes the <code>XMLFragment</code> with the content from the given <code>InputStream</code>. Sets the
372         * SystemId, too.
373         *
374         * @param istream
375         * @param systemId
376         *            cannot be null. This string should represent a URL that is related to the passed istream. If this URL
377         *            is not available or unknown, the string should contain the value of XMLFragment.DEFAULT_URL
378         * @throws SAXException
379         * @throws IOException
380         * @throws XMLException
381         * @throws NullPointerException
382         */
383        public void load( InputStream istream, String systemId )
384                                throws SAXException, IOException, XMLException {
385    
386            PushbackInputStream pbis = new PushbackInputStream( istream, 1024 );
387            String encoding = readEncoding( pbis );
388    
389            if ( LOG.isDebug() ) {
390                LOG.logDebug( "Reading XMLFragment " + systemId + " with encoding ", encoding );
391            }
392    
393            InputStreamReader isr = new InputStreamReader( pbis, encoding );
394            load( isr, systemId );
395        }
396    
397        /**
398         * reads the encoding of a XML document from its header. If no header available
399         * <code>CharsetUtils.getSystemCharset()</code> will be returned
400         *
401         * @param pbis
402         * @return encoding of a XML document
403         * @throws IOException
404         */
405        private String readEncoding( PushbackInputStream pbis )
406                                throws IOException {
407            byte[] b = new byte[80];
408            String s = "";
409            int rd = 0;
410    
411            LinkedList<byte[]> bs = new LinkedList<byte[]>();
412            LinkedList<Integer> rds = new LinkedList<Integer>();
413            while ( rd < 80 ) {
414                rds.addFirst( pbis.read( b ) );
415                if ( rds.peek() == -1 ) {
416                    rds.poll();
417                    break;
418                }
419                rd += rds.peek();
420                s += new String( b, 0, rds.peek() ).toLowerCase();
421                bs.addFirst( b );
422                b = new byte[80];
423            }
424    
425            String encoding = CharsetUtils.getSystemCharset();
426            if ( s.indexOf( "?>" ) > -1 ) {
427                int p = s.indexOf( "encoding=" );
428                if ( p > -1 ) {
429                    StringBuffer sb = new StringBuffer();
430                    int k = p + 1 + "encoding=".length();
431                    while ( s.charAt( k ) != '"' && s.charAt( k ) != '\'' ) {
432                        sb.append( s.charAt( k++ ) );
433                    }
434                    encoding = sb.toString();
435                }
436            }
437            while ( !bs.isEmpty() ) {
438                pbis.unread( bs.poll(), 0, rds.poll() );
439            }
440    
441            return encoding;
442        }
443    
444        /**
445         * Initializes the <code>XMLFragment</code> with the content from the given <code>Reader</code>. Sets the SystemId,
446         * too.
447         *
448         * @param reader
449         * @param systemId
450         *            can not be null. This string should represent a URL that is related to the passed reader. If this URL
451         *            is not available or unknown, the string should contain the value of XMLFragment.DEFAULT_URL
452         * @throws SAXException
453         * @throws IOException
454         * @throws NullPointerException
455         */
456        public void load( Reader reader, String systemId )
457                                throws SAXException, IOException {
458    
459            PushbackReader pbr = new PushbackReader( reader, 1024 );
460            int c = pbr.read();
461            if ( c != 65279 && c != 65534 ) {
462                // no BOM! push char back into reader
463                pbr.unread( c );
464            }
465    
466            InputSource source = new InputSource( pbr );
467            if ( systemId == null ) {
468                throw new NullPointerException( "'systemId' must not be null!" );
469            }
470            setSystemId( systemId );
471            DocumentBuilder builder = XMLTools.getDocumentBuilder();
472            Document doc = builder.parse( source );
473            setRootElement( doc.getDocumentElement() );
474        }
475    
476        /**
477         * @param rootElement
478         */
479        public void setRootElement( Element rootElement ) {
480            this.rootElement = rootElement;
481        }
482    
483        /**
484         * @return the element
485         */
486        public Element getRootElement() {
487            return rootElement;
488        }
489    
490        /**
491         * Resolves the given URL (which may be relative) against the SystemID of the <code>XMLFragment</code> into a
492         * <code>URL</code> (which is always absolute).
493         *
494         * @param url
495         * @return the resolved URL object
496         * @throws MalformedURLException
497         */
498        public URL resolve( String url )
499                                throws MalformedURLException {
500            LOG.logDebug( StringTools.concat( 200, "Resolving URL '", url, "' against SystemID '", systemId,
501                                              "' of XMLFragment" ) );
502    
503            URL resolvedURL = FileUtils.resolt( systemId, url );
504    
505            LOG.logDebug( StringTools.concat( 100, "-> resolvedURL: '", resolvedURL, "'" ) );
506            return resolvedURL;
507        }
508    
509        /**
510         * Writes the <code>XMLFragment</code> instance to the given <code>Writer</code> using the default system encoding
511         * and adding CDATA-sections in for text-nodes where needed.
512         *
513         * TODO: Add code for CDATA safety.
514         *
515         * @param writer
516         */
517        public void write( Writer writer ) {
518            Properties properties = new Properties();
519            properties.setProperty( OutputKeys.ENCODING, CharsetUtils.getSystemCharset() );
520            write( writer, properties );
521        }
522    
523        /**
524         * Writes the <code>XMLFragment</code> instance to the given <code>Writer</code> using the specified
525         * <code>OutputKeys</code>.
526         *
527         * @param writer
528         *            cannot be null
529         * @param outputProperties
530         *            output properties for the <code>Transformer</code> that is used to serialize the document
531         *
532         *            see javax.xml.OutputKeys
533         */
534        public void write( Writer writer, Properties outputProperties ) {
535            try {
536                Source source = new DOMSource( rootElement );
537                Transformer transformer = TransformerFactory.newInstance().newTransformer();
538                if ( outputProperties != null ) {
539                    transformer.setOutputProperties( outputProperties );
540                }
541                transformer.transform( source, new StreamResult( writer ) );
542            } catch ( TransformerConfigurationException e ) {
543                LOG.logError( e.getMessage(), e );
544                throw new XMLException( e );
545            } catch ( Exception e ) {
546                LOG.logError( e.getMessage(), e );
547                throw new XMLException( e );
548            }
549        }
550    
551        /**
552         * Writes the <code>XMLFragment</code> instance to the given <code>OutputStream</code> using the default system
553         * encoding and adding CDATA-sections in for text-nodes where needed.
554         *
555         * TODO: Add code for CDATA safety.
556         *
557         * @param os
558         */
559        public void write( OutputStream os ) {
560            Properties properties = new Properties();
561            properties.setProperty( OutputKeys.ENCODING, CharsetUtils.getSystemCharset() );
562            write( os, properties );
563        }
564    
565        /**
566         * Writes the <code>XMLFragment</code> instance to the given <code>OutputStream</code> using the specified
567         * <code>OutputKeys</code> which allow complete control of the generated output.
568         *
569         * @param os
570         *            cannot be null
571         * @param outputProperties
572         *            output properties for the <code>Transformer</code> used to serialize the document
573         *
574         * @see javax.xml.transform.OutputKeys
575         */
576        public void write( OutputStream os, Properties outputProperties ) {
577            try {
578                Source source = new DOMSource( rootElement );
579                Transformer transformer = TransformerFactory.newInstance().newTransformer();
580                if ( outputProperties != null ) {
581                    transformer.setOutputProperties( outputProperties );
582                }
583                transformer.transform( source, new StreamResult( os ) );
584            } catch ( TransformerConfigurationException e ) {
585                LOG.logError( e.getMessage(), e );
586                throw new XMLException( e );
587            } catch ( Exception e ) {
588                LOG.logError( e.getMessage(), e );
589                throw new XMLException( e );
590            }
591        }
592    
593        /**
594         * Writes the <code>XMLFragment</code> instance to the given <code>OutputStream</code> using indentation so it may
595         * be read easily.
596         *
597         * @param os
598         * @throws TransformerException
599         */
600        public void prettyPrint( OutputStream os )
601                                throws TransformerException {
602            InputStream xsl = XMLFragment.class.getResourceAsStream( "PrettyPrinter.xsl" );
603            Transformer transformer = TransformerFactory.newInstance().newTransformer( new StreamSource( xsl ) );
604            transformer.transform( new DOMSource( rootElement ), new StreamResult( os ) );
605        }
606    
607        /**
608         * Writes the <code>XMLFragment</code> instance to the given <code>Writer</code> using indentation so it may be read
609         * easily.
610         *
611         * @param writer
612         * @throws TransformerException
613         */
614        public void prettyPrint( Writer writer )
615                                throws TransformerException {
616            InputStream xsl = XMLFragment.class.getResourceAsStream( "PrettyPrinter.xsl" );
617            Transformer transformer = TransformerFactory.newInstance().newTransformer( new StreamSource( xsl ) );
618            transformer.transform( new DOMSource( rootElement ), new StreamResult( writer ) );
619        }
620    
621        /**
622         * Parses the submitted <code>Element</code> as a <code>SimpleLink</code>.
623         * <p>
624         * Possible escaping of the attributes "xlink:href", "xlink:role" and "xlink:arcrole" is performed automatically.
625         * </p>
626         *
627         * @param element
628         * @return the object representation of the element
629         * @throws XMLParsingException
630         */
631        protected SimpleLink parseSimpleLink( Element element )
632                                throws XMLParsingException {
633    
634            URI href = null;
635            URI role = null;
636            URI arcrole = null;
637            String title = null;
638            String show = null;
639            String actuate = null;
640    
641            String uriString = null;
642            try {
643                uriString = XMLTools.getNodeAsString( element, "@xlink:href", nsContext, null );
644                if ( uriString != null ) {
645                    href = new URI( null, uriString, null );
646                }
647                uriString = XMLTools.getNodeAsString( element, "@xlink:role", nsContext, null );
648                if ( uriString != null ) {
649                    role = new URI( null, uriString, null );
650                }
651                uriString = XMLTools.getNodeAsString( element, "@xlink:arcrole", nsContext, null );
652                if ( uriString != null ) {
653                    arcrole = new URI( null, uriString, null );
654                }
655            } catch ( URISyntaxException e ) {
656                throw new XMLParsingException( "'" + uriString + "' is not a valid URI." );
657            }
658    
659            return new SimpleLink( href, role, arcrole, title, show, actuate );
660        }
661    
662        /**
663         * Parses the value of the submitted <code>Node</code> as a <code>QualifiedName</code>.
664         * <p>
665         * To parse the text contents of an <code>Element</code> node, the actual text node must be given, not the
666         * <code>Element</code> node itself.
667         * </p>
668         *
669         * @param node
670         * @return object representation of the element
671         * @throws XMLParsingException
672         */
673        public static QualifiedName parseQualifiedName( Node node )
674                                throws XMLParsingException {
675    
676            String name = node.getNodeValue().trim();
677            QualifiedName qName = null;
678            if ( name.indexOf( ':' ) > -1 ) {
679                String[] tmp = StringTools.toArray( name, ":", false );
680                try {
681                    qName = new QualifiedName( tmp[0], tmp[1], XMLTools.getNamespaceForPrefix( tmp[0], node ) );
682                } catch ( URISyntaxException e ) {
683                    throw new XMLParsingException( e.getMessage(), e );
684                }
685            } else {
686                qName = new QualifiedName( name );
687            }
688            return qName;
689        }
690    
691        /**
692         * Returns the qualified name of the given element.
693         *
694         * @param element
695         * @return the qualified name of the given element.
696         * @throws XMLParsingException
697         */
698        protected QualifiedName getQualifiedName( Element element )
699                                throws XMLParsingException {
700    
701            // TODO check if we can use element.getNamespaceURI() instead
702            URI nsURI = null;
703            String prefix = element.getPrefix();
704            try {
705                nsURI = XMLTools.getNamespaceForPrefix( prefix, element );
706            } catch ( URISyntaxException e ) {
707                String msg = Messages.format( "ERROR_NSURI_NO_URI", element.getPrefix() );
708                LOG.logError( msg, e );
709                throw new XMLParsingException( msg, e );
710            }
711            QualifiedName ftName = new QualifiedName( prefix, element.getLocalName(), nsURI );
712    
713            return ftName;
714        }
715    
716        /**
717         * Returns a string representation of the XML Document
718         *
719         * @return the string
720         */
721        public String getAsString() {
722            StringWriter writer = new StringWriter( 50000 );
723            Source source = new DOMSource( rootElement );
724            try {
725                Transformer transformer = TransformerFactory.newInstance().newTransformer();
726                transformer.setOutputProperty( "encoding", CharsetUtils.getSystemCharset() );
727                transformer.transform( source, new StreamResult( writer ) );
728            } catch ( Exception e ) {
729                LOG.logError( "Error serializing XMLFragment!", e );
730            }
731            return writer.toString();
732        }
733    
734        /**
735         * Returns a string representation of the XML Document, pretty printed. Note that pretty printing can mess up XML
736         * documents in some cases (GML, for instance).
737         *
738         * @return the string
739         */
740        public String getAsPrettyString() {
741            StringWriter writer = new StringWriter( 50000 );
742            try {
743                prettyPrint( writer );
744            } catch ( TransformerException e ) {
745                LOG.logError( "Error pretty printing XMLFragment!", e );
746            }
747            return writer.toString();
748        }
749    
750        /**
751         * Returns a string representation of the object.
752         *
753         * @return a string representation of the object.
754         */
755        @Override
756        public String toString() {
757            return getAsString();
758        }
759    }