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. <!ENTITY local SYSTEM 106 * "conf/wfs/wfs.cfg"></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 }