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