Coverage Report - org.mule.module.xml.util.XMLUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
XMLUtils
0%
0/202
0%
0/154
0
XMLUtils$1
0%
0/7
N/A
0
XMLUtils$XPathNamespaceContext
0%
0/10
0%
0/4
0
 
 1  
 /*
 2  
  * $Id: XMLUtils.java 19191 2010-08-25 21:05:23Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.module.xml.util;
 12  
 
 13  
 import org.mule.DefaultMuleMessage;
 14  
 import org.mule.RequestContext;
 15  
 import org.mule.api.MuleContext;
 16  
 import org.mule.api.MuleMessage;
 17  
 import org.mule.api.transport.OutputHandler;
 18  
 import org.mule.module.xml.stax.DelegateXMLStreamReader;
 19  
 import org.mule.module.xml.stax.StaxSource;
 20  
 import org.mule.module.xml.transformer.DelayedResult;
 21  
 import org.mule.module.xml.transformer.XmlToDomDocument;
 22  
 import org.mule.transformer.types.DataTypeFactory;
 23  
 import org.mule.util.IOUtils;
 24  
 
 25  
 import java.io.ByteArrayInputStream;
 26  
 import java.io.File;
 27  
 import java.io.FileReader;
 28  
 import java.io.IOException;
 29  
 import java.io.InputStream;
 30  
 import java.io.InputStreamReader;
 31  
 import java.io.Reader;
 32  
 import java.io.StringReader;
 33  
 import java.util.ArrayList;
 34  
 import java.util.Iterator;
 35  
 import java.util.List;
 36  
 
 37  
 import javax.xml.parsers.DocumentBuilderFactory;
 38  
 import javax.xml.namespace.NamespaceContext;
 39  
 import javax.xml.stream.XMLStreamConstants;
 40  
 import javax.xml.stream.XMLStreamException;
 41  
 import javax.xml.stream.XMLStreamReader;
 42  
 import javax.xml.stream.XMLStreamWriter;
 43  
 import javax.xml.transform.Source;
 44  
 import javax.xml.transform.Transformer;
 45  
 import javax.xml.transform.TransformerConfigurationException;
 46  
 import javax.xml.transform.TransformerFactory;
 47  
 import javax.xml.transform.TransformerFactoryConfigurationError;
 48  
 import javax.xml.transform.dom.DOMResult;
 49  
 import javax.xml.transform.dom.DOMSource;
 50  
 import javax.xml.transform.sax.SAXSource;
 51  
 import javax.xml.transform.stream.StreamSource;
 52  
 import javax.xml.xpath.XPath;
 53  
 import javax.xml.xpath.XPathConstants;
 54  
 import javax.xml.xpath.XPathExpressionException;
 55  
 import javax.xml.xpath.XPathFactory;
 56  
 
 57  
 import org.apache.commons.io.output.ByteArrayOutputStream;
 58  
 import org.apache.commons.lang.StringUtils;
 59  
 import org.dom4j.DocumentException;
 60  
 import org.dom4j.io.DOMReader;
 61  
 import org.dom4j.io.DOMWriter;
 62  
 import org.dom4j.io.DocumentSource;
 63  
 import org.w3c.dom.Document;
 64  
 import org.w3c.dom.Node;
 65  
 import org.w3c.dom.NodeList;
 66  
 import org.xml.sax.InputSource;
 67  
 
 68  
 /**
 69  
  * General utility methods for working with XML.
 70  
  */
 71  0
 public class XMLUtils extends org.mule.util.XMLUtils
 72  
 {
 73  
     public static final String TRANSFORMER_FACTORY_JDK5 = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
 74  
 
 75  
     // xml parser feature names for optional XSD validation
 76  
     public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA = "http://apache.org/xml/features/validation/schema";
 77  
     public static final String APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING = "http://apache.org/xml/features/validation/schema-full-checking";
 78  
 
 79  
     // JAXP property for specifying external XSD location
 80  
     public static final String JAXP_PROPERTIES_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
 81  
 
 82  
     // JAXP properties for specifying external XSD language (as required by newer
 83  
     // JAXP implementation)
 84  
     public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
 85  
     public static final String JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE = "http://www.w3.org/2001/XMLSchema";
 86  
 
 87  
     /**
 88  
      * Converts a DOM to an XML string.
 89  
      * @param dom the dome object to convert
 90  
      * @return A string representation of the document
 91  
      */
 92  
     public static String toXml(Document dom)
 93  
     {
 94  0
         return new DOMReader().read(dom).asXML();
 95  
     }
 96  
 
 97  
     /**
 98  
      * @return a new XSLT transformer
 99  
      * @throws TransformerConfigurationException if no TransformerFactory can be located in the
 100  
      * runtime environment.
 101  
      */
 102  
     public static Transformer getTransformer() throws TransformerConfigurationException
 103  
     {
 104  
         TransformerFactory tf;
 105  
         try
 106  
         {
 107  0
             tf = TransformerFactory.newInstance();
 108  
         }
 109  0
         catch (TransformerFactoryConfigurationError e)
 110  
         {
 111  0
             System.setProperty("javax.xml.transform.TransformerFactory", TRANSFORMER_FACTORY_JDK5);
 112  0
             tf = TransformerFactory.newInstance();
 113  0
         }
 114  0
         if (tf != null)
 115  
         {
 116  0
             return tf.newTransformer();
 117  
         }
 118  
         else
 119  
         {
 120  0
             throw new TransformerConfigurationException("Unable to instantiate a TransformerFactory");
 121  
         }
 122  
     }
 123  
 
 124  
     public static org.dom4j.Document toDocument(Object obj, MuleContext muleContext) throws Exception
 125  
     {
 126  0
         return toDocument(obj, null, muleContext);
 127  
     }
 128  
     
 129  
     /**
 130  
      * Converts an object of unknown type to an org.dom4j.Document if possible.
 131  
      * @return null if object cannot be converted
 132  
      * @throws DocumentException if an error occurs while parsing
 133  
      */
 134  
     public static org.dom4j.Document toDocument(Object obj, String externalSchemaLocation, MuleContext muleContext) throws Exception
 135  
     {
 136  0
         org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
 137  0
         if (externalSchemaLocation != null)
 138  
         {
 139  0
             reader.setValidation(true);
 140  0
             reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA, true);
 141  0
             reader.setFeature(APACHE_XML_FEATURES_VALIDATION_SCHEMA_FULL_CHECKING, true);
 142  
             
 143  0
             InputStream xsdAsStream = IOUtils.getResourceAsStream(externalSchemaLocation, XMLUtils.class);
 144  0
             if (xsdAsStream == null)
 145  
             {
 146  0
                 throw new IllegalArgumentException("Couldn't find schema at " + externalSchemaLocation);
 147  
             }
 148  
     
 149  
             // Set schema language property (must be done before the schemaSource
 150  
             // is set)
 151  0
             reader.setProperty(JAXP_PROPERTIES_SCHEMA_LANGUAGE, JAXP_PROPERTIES_SCHEMA_LANGUAGE_VALUE);
 152  
     
 153  
             // Need this one to map schemaLocation to a physical location
 154  0
             reader.setProperty(JAXP_PROPERTIES_SCHEMA_SOURCE, xsdAsStream);
 155  
         }
 156  
 
 157  
 
 158  0
         if (obj instanceof org.dom4j.Document)
 159  
         {
 160  0
             return (org.dom4j.Document) obj;
 161  
         }
 162  0
         else if (obj instanceof org.w3c.dom.Document)
 163  
         {
 164  0
             org.dom4j.io.DOMReader domReader = new org.dom4j.io.DOMReader();
 165  0
             return domReader.read((org.w3c.dom.Document) obj);
 166  
         }
 167  0
         else if (obj instanceof org.xml.sax.InputSource)
 168  
         {                
 169  0
             return reader.read((org.xml.sax.InputSource) obj);
 170  
         }
 171  0
         else if (obj instanceof javax.xml.transform.Source || obj instanceof javax.xml.stream.XMLStreamReader)
 172  
         {                
 173  
             // TODO Find a more direct way to do this
 174  0
             XmlToDomDocument tr = new XmlToDomDocument();
 175  0
             tr.setMuleContext(muleContext);
 176  0
             tr.setReturnDataType(DataTypeFactory.create(org.dom4j.Document.class));
 177  0
             return (org.dom4j.Document) tr.transform(obj);
 178  
         }
 179  0
         else if (obj instanceof java.io.InputStream)
 180  
         {                
 181  0
             return reader.read((java.io.InputStream) obj);
 182  
         }
 183  0
         else if (obj instanceof String)
 184  
         {
 185  0
             return reader.read(new StringReader((String) obj));
 186  
         }
 187  0
         else if (obj instanceof byte[])
 188  
         {
 189  
             // TODO Handle encoding/charset somehow
 190  0
             return reader.read(new StringReader(new String((byte[]) obj)));
 191  
         }
 192  0
         else if (obj instanceof File)
 193  
         {                
 194  0
             return reader.read((File) obj);
 195  
         }
 196  
         else
 197  
         {
 198  0
             return null;
 199  
         }
 200  
     }
 201  
 
 202  
     /**
 203  
      * Converts a payload to a {@link org.w3c.dom.Document} representation.
 204  
      * <p> Reproduces the behavior from {@link org.mule.module.xml.util.XMLUtils#toDocument(Object, MuleContext)}
 205  
      * which works converting to {@link org.dom4j.Document}.
 206  
      *
 207  
      * @param payload the payload to convert.
 208  
      * @return a document from the payload or null if the payload is not a valid XML document.
 209  
      */
 210  
     public static org.w3c.dom.Document toW3cDocument(Object payload) throws Exception
 211  
     {
 212  0
         if (payload instanceof org.dom4j.Document)
 213  
         {
 214  0
             DOMWriter writer = new DOMWriter();
 215  0
             org.w3c.dom.Document w3cDocument = writer.write((org.dom4j.Document) payload);
 216  
 
 217  0
             return w3cDocument;
 218  
         }
 219  0
         else if (payload instanceof org.w3c.dom.Document)
 220  
         {
 221  0
             return (org.w3c.dom.Document) payload;
 222  
         }
 223  0
         else if (payload instanceof org.xml.sax.InputSource)
 224  
         {
 225  0
             return parseXML((InputSource) payload);
 226  
         }
 227  0
         else if (payload instanceof javax.xml.transform.Source || payload instanceof javax.xml.stream.XMLStreamReader)
 228  
         {
 229  0
             DOMResult result = new DOMResult();
 230  0
             Transformer idTransformer = getTransformer();
 231  0
             Source source = (payload instanceof Source) ? (Source)payload : toXmlSource(null, true, payload);
 232  0
             idTransformer.transform(source, result);
 233  0
             return (Document) result.getNode();
 234  
         }
 235  0
         else if (payload instanceof java.io.InputStream)
 236  
         {
 237  0
             InputStreamReader input = new InputStreamReader((InputStream) payload);
 238  0
             return parseXML(input);
 239  
         }
 240  0
         else if (payload instanceof String)
 241  
         {
 242  0
             Reader input = new StringReader((String) payload);
 243  
 
 244  0
             return parseXML(input);
 245  
         }
 246  0
         else if (payload instanceof byte[])
 247  
         {
 248  
             // TODO Handle encoding/charset somehow
 249  0
             Reader input = new StringReader(new String((byte[]) payload));
 250  0
             return parseXML(input);
 251  
         }
 252  0
         else if (payload instanceof File)
 253  
         {
 254  0
             Reader input = new FileReader((File) payload);
 255  0
             return parseXML(input);
 256  
         }
 257  
         else
 258  
         {
 259  0
             return null;
 260  
         }
 261  
     }
 262  
 
 263  
     private static org.w3c.dom.Document parseXML(Reader source) throws Exception
 264  
     {
 265  0
         return parseXML(new InputSource(source));
 266  
     }
 267  
 
 268  
     private static org.w3c.dom.Document parseXML(InputSource source) throws Exception
 269  
     {
 270  0
         DocumentBuilderFactory factory =
 271  
                 DocumentBuilderFactory.newInstance();
 272  
 
 273  0
         return factory.newDocumentBuilder().parse(source);
 274  
     }
 275  
 
 276  
     /**
 277  
      * Returns an XMLStreamReader for an object of unknown type if possible.
 278  
      * @return null if no XMLStreamReader can be created for the object type
 279  
      * @throws XMLStreamException
 280  
      */
 281  
     public static javax.xml.stream.XMLStreamReader toXMLStreamReader(javax.xml.stream.XMLInputFactory factory, Object obj) throws XMLStreamException
 282  
     {
 283  0
         if (obj instanceof javax.xml.stream.XMLStreamReader)
 284  
         {
 285  0
             return (javax.xml.stream.XMLStreamReader) obj;
 286  
         }
 287  0
         else if (obj instanceof org.mule.module.xml.stax.StaxSource)
 288  
         {
 289  0
             return ((org.mule.module.xml.stax.StaxSource) obj).getXMLStreamReader();
 290  
         }
 291  0
         else if (obj instanceof javax.xml.transform.Source)
 292  
         {
 293  0
             return factory.createXMLStreamReader((javax.xml.transform.Source) obj);
 294  
         }
 295  0
         else if (obj instanceof org.xml.sax.InputSource)
 296  
         {
 297  0
             return factory.createXMLStreamReader(((org.xml.sax.InputSource) obj).getByteStream());
 298  
         }
 299  0
         else if (obj instanceof org.w3c.dom.Document)
 300  
         {
 301  0
             return factory.createXMLStreamReader(new javax.xml.transform.dom.DOMSource((org.w3c.dom.Document) obj));
 302  
         }
 303  0
         else if (obj instanceof org.dom4j.Document)
 304  
         {
 305  0
             return factory.createXMLStreamReader(new org.dom4j.io.DocumentSource((org.dom4j.Document) obj));
 306  
         }
 307  0
         else if (obj instanceof java.io.InputStream)
 308  
         {
 309  0
             final InputStream is = (java.io.InputStream) obj;
 310  
             
 311  0
             XMLStreamReader xsr = factory.createXMLStreamReader(is);
 312  0
             return new DelegateXMLStreamReader(xsr) 
 313  0
             {
 314  
                 @Override
 315  
                 public void close() throws XMLStreamException
 316  
                 {
 317  0
                     super.close();
 318  
                     
 319  
                     try
 320  
                     {
 321  0
                         is.close();
 322  
                     }
 323  0
                     catch (IOException e)
 324  
                     {
 325  0
                         throw new XMLStreamException(e);
 326  0
                     }
 327  0
                 }
 328  
                 
 329  
             };
 330  
         }
 331  0
         else if (obj instanceof String)
 332  
         {
 333  0
             return factory.createXMLStreamReader(new StringReader((String) obj));
 334  
         }
 335  0
         else if (obj instanceof byte[])
 336  
         {
 337  
             // TODO Handle encoding/charset?
 338  0
             return factory.createXMLStreamReader(new ByteArrayInputStream((byte[]) obj));
 339  
         }
 340  
         else
 341  
         {
 342  0
             return null;
 343  
         }
 344  
     }
 345  
     
 346  
     /**
 347  
      * Convert our object to a Source type efficiently.
 348  
      */ 
 349  
     public static javax.xml.transform.Source toXmlSource(javax.xml.stream.XMLInputFactory xmlInputFactory, boolean useStaxSource, Object src) throws Exception
 350  
     {
 351  0
         if (src instanceof javax.xml.transform.Source)
 352  
         {
 353  0
             return (Source) src;
 354  
         }
 355  0
         else if (src instanceof byte[])
 356  
         {
 357  0
             ByteArrayInputStream stream = new ByteArrayInputStream((byte[]) src);
 358  0
             return toStreamSource(xmlInputFactory, useStaxSource, stream);
 359  
         }
 360  0
         else if (src instanceof InputStream)
 361  
         {
 362  0
             return toStreamSource(xmlInputFactory, useStaxSource, (InputStream) src);
 363  
         }
 364  0
         else if (src instanceof String)
 365  
         {
 366  0
             if (useStaxSource)
 367  
             {
 368  0
                 return new StaxSource(xmlInputFactory.createXMLStreamReader(new StringReader((String) src)));
 369  
             }
 370  
             else
 371  
             {
 372  0
                 return new StreamSource(new StringReader((String) src));
 373  
             }
 374  
         }
 375  0
         else if (src instanceof org.dom4j.Document)
 376  
         {
 377  0
             return new DocumentSource((org.dom4j.Document) src);
 378  
         }
 379  0
         else if (src instanceof org.xml.sax.InputSource)
 380  
         {
 381  0
             return new SAXSource((InputSource) src);
 382  
         }
 383  
         // TODO MULE-3555
 384  0
         else if (src instanceof XMLStreamReader)
 385  
         {
 386  0
             XMLStreamReader xsr = (XMLStreamReader) src;
 387  
             
 388  
             // StaxSource requires that we advance to a start element/document event
 389  0
             if (!xsr.isStartElement() && 
 390  
                             xsr.getEventType() != XMLStreamConstants.START_DOCUMENT) 
 391  
             {
 392  0
                 xsr.nextTag();
 393  
             }
 394  
             
 395  0
             return new StaxSource((XMLStreamReader) src);
 396  
         }
 397  0
         else if (src instanceof org.w3c.dom.Document || src instanceof org.w3c.dom.Element)
 398  
         {
 399  0
             return new DOMSource((org.w3c.dom.Node) src);
 400  
         }
 401  0
         else if (src instanceof DelayedResult) 
 402  
         {
 403  0
             DelayedResult result = ((DelayedResult) src);
 404  0
             DOMResult domResult = new DOMResult();
 405  0
             result.write(domResult);
 406  0
             return new DOMSource(domResult.getNode());
 407  
         }
 408  0
         else if (src instanceof OutputHandler) 
 409  
         {
 410  0
             OutputHandler handler = ((OutputHandler) src);
 411  0
             ByteArrayOutputStream output = new ByteArrayOutputStream();
 412  
             
 413  0
             handler.write(RequestContext.getEvent(), output);
 414  
             
 415  0
             return toStreamSource(xmlInputFactory, useStaxSource, new ByteArrayInputStream(output.toByteArray()));
 416  
         }
 417  
         else
 418  
         {
 419  0
             return null;
 420  
         }
 421  
     }
 422  
 
 423  
     public static javax.xml.transform.Source toStreamSource(javax.xml.stream.XMLInputFactory xmlInputFactory, boolean useStaxSource, InputStream stream) throws XMLStreamException
 424  
     {
 425  0
         if (useStaxSource)
 426  
         {
 427  0
             return new org.mule.module.xml.stax.StaxSource(xmlInputFactory.createXMLStreamReader(stream));
 428  
         }
 429  
         else 
 430  
         {
 431  0
             return new javax.xml.transform.stream.StreamSource(stream);
 432  
         }
 433  
     }
 434  
     
 435  
     /**
 436  
      * Copies the reader to the writer. The start and end document methods must
 437  
      * be handled on the writer manually. TODO: if the namespace on the reader
 438  
      * has been declared previously to where we are in the stream, this probably
 439  
      * won't work.
 440  
      * 
 441  
      * @param reader
 442  
      * @param writer
 443  
      * @throws XMLStreamException
 444  
      */
 445  
     public static void copy(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
 446  0
         copy(reader, writer, false);
 447  0
     }
 448  
     public static void copy(XMLStreamReader reader, XMLStreamWriter writer,
 449  
                             boolean fragment) throws XMLStreamException {
 450  
         // number of elements read in
 451  0
         int read = 0;
 452  0
         int event = reader.getEventType();
 453  
 
 454  0
         while (reader.hasNext()) {
 455  0
             switch (event) {
 456  
             case XMLStreamConstants.START_ELEMENT:
 457  0
                 read++;
 458  0
                 writeStartElement(reader, writer);
 459  0
                 break;
 460  
             case XMLStreamConstants.END_ELEMENT:
 461  0
                 writer.writeEndElement();
 462  0
                 read--;
 463  0
                 if (read <= 0 && !fragment) {
 464  0
                     return;
 465  
                 }
 466  
                 break;
 467  
             case XMLStreamConstants.CHARACTERS:
 468  0
                 writer.writeCharacters(reader.getText());
 469  0
                 break;
 470  
             case XMLStreamConstants.START_DOCUMENT:
 471  
             case XMLStreamConstants.END_DOCUMENT:
 472  
             case XMLStreamConstants.ATTRIBUTE:
 473  
             case XMLStreamConstants.NAMESPACE:
 474  0
                 break;
 475  
             default:
 476  
                 break;
 477  
             }
 478  0
             event = reader.next();
 479  
         }
 480  0
     }
 481  
 
 482  
     private static void writeStartElement(XMLStreamReader reader, XMLStreamWriter writer)
 483  
         throws XMLStreamException {
 484  0
         String local = reader.getLocalName();
 485  0
         String uri = reader.getNamespaceURI();
 486  0
         String prefix = reader.getPrefix();
 487  0
         if (prefix == null) {
 488  0
             prefix = "";
 489  
         }
 490  
 
 491  
         
 492  
 //        System.out.println("STAXUTILS:writeStartElement : node name : " + local +  " namespace URI" + uri);
 493  0
         boolean writeElementNS = false;
 494  0
         if (uri != null) {
 495  0
             String boundPrefix = writer.getPrefix(uri);
 496  0
             if (boundPrefix == null || !prefix.equals(boundPrefix)) {
 497  0
                 writeElementNS = true;
 498  
             }
 499  
         }
 500  
 
 501  
         // Write out the element name
 502  0
         if (uri != null) {
 503  0
             if (prefix.length() == 0 && StringUtils.isEmpty(uri)) {
 504  0
                 writer.writeStartElement(local);
 505  0
                 writer.setDefaultNamespace(uri);
 506  
 
 507  
             } else {
 508  0
                 writer.writeStartElement(prefix, local, uri);
 509  0
                 writer.setPrefix(prefix, uri);
 510  
             }
 511  
         } else {
 512  0
             writer.writeStartElement(local);
 513  
         }
 514  
 
 515  
         // Write out the namespaces
 516  0
         for (int i = 0; i < reader.getNamespaceCount(); i++) {
 517  0
             String nsURI = reader.getNamespaceURI(i);
 518  0
             String nsPrefix = reader.getNamespacePrefix(i);
 519  0
             if (nsPrefix == null) {
 520  0
                 nsPrefix = "";
 521  
             }
 522  
 
 523  0
             if (nsPrefix.length() == 0) {
 524  0
                 writer.writeDefaultNamespace(nsURI);
 525  
             } else {
 526  0
                 writer.writeNamespace(nsPrefix, nsURI);
 527  
             }
 528  
 
 529  0
             if (nsURI.equals(uri) && nsPrefix.equals(prefix)) {
 530  0
                 writeElementNS = false;
 531  
             }
 532  
         }
 533  
 
 534  
         // Check if the namespace still needs to be written.
 535  
         // We need this check because namespace writing works
 536  
         // different on Woodstox and the RI.
 537  0
         if (writeElementNS) {
 538  0
             if (prefix.length() == 0) {
 539  0
                 writer.writeDefaultNamespace(uri);
 540  
             } else {
 541  0
                 writer.writeNamespace(prefix, uri);
 542  
             }
 543  
         }        
 544  
         
 545  
         // Write out attributes
 546  0
         for (int i = 0; i < reader.getAttributeCount(); i++) {
 547  0
             String ns = reader.getAttributeNamespace(i);
 548  0
             String nsPrefix = reader.getAttributePrefix(i);
 549  0
             if (ns == null || ns.length() == 0) {
 550  0
                 writer.writeAttribute(reader.getAttributeLocalName(i), reader.getAttributeValue(i));
 551  0
             } else if (nsPrefix == null || nsPrefix.length() == 0) {
 552  0
                 writer.writeAttribute(reader.getAttributeNamespace(i), reader.getAttributeLocalName(i),
 553  
                                       reader.getAttributeValue(i));
 554  
             } else {
 555  0
                 writer.writeAttribute(reader.getAttributePrefix(i), reader.getAttributeNamespace(i), reader
 556  
                     .getAttributeLocalName(i), reader.getAttributeValue(i));
 557  
             }
 558  
 
 559  
         }
 560  0
     }
 561  
 
 562  
     /**
 563  
      * Creates an XPath object with a custom NamespaceContext given the Node to operate on
 564  
      * @param node the Node or document to operate on.  Note that namespace handling will not work if a Node fragment is passed in
 565  
      * @return a new XPath object
 566  
      */
 567  
     private static XPath createXPath(Node node)
 568  
     {
 569  0
         XPath xp = XPathFactory.newInstance().newXPath();
 570  0
         if (node instanceof Document)
 571  
         {
 572  0
             xp.setNamespaceContext(new XPathNamespaceContext((Document) node));
 573  
         }
 574  0
         return xp;
 575  
     }
 576  
 
 577  
     /**
 578  
      * Select a single XML node using an Xpath
 579  
      * @param xpath the XPath expression to evaluate
 580  
      * @param node the node (or document) to exaluate on
 581  
      * @return the result of the evaluation.
 582  
      * @throws XPathExpressionException if the XPath expression is malformed and cannot be parsed
 583  
      */
 584  
     public static Node selectOne(String xpath, Node node) throws XPathExpressionException
 585  
     {
 586  0
             XPath xp = createXPath(node);
 587  0
             return (Node) xp.evaluate(xpath, node, XPathConstants.NODE);
 588  
     }
 589  
 
 590  
     /**
 591  
      * Select a single XML String value using an Xpath
 592  
      * @param xpath the XPath expression to evaluate
 593  
      * @param node the node (or document) to evaluate on
 594  
      * @return the result of the evaluation.
 595  
      * @throws XPathExpressionException if the XPath expression is malformed and cannot be parsed
 596  
      */
 597  
     public static String selectValue(String xpath, Node node) throws XPathExpressionException
 598  
     {
 599  0
             XPath xp = createXPath(node);
 600  0
             return (String) xp.evaluate(xpath, node, XPathConstants.STRING);
 601  
     }
 602  
 
 603  
     /**
 604  
      * Select a set of Node objects using the Xpath expression
 605  
      * @param xpath the XPath expression to evaluate
 606  
      * @param node the node (or document) to evaluate on
 607  
      * @return the result of the evaluation. 
 608  
      * @throws XPathExpressionException if the XPath expression is malformed and cannot be parsed
 609  
      */
 610  
     public static List<Node> select(String xpath, Node node) throws XPathExpressionException
 611  
     {
 612  0
             XPath xp = createXPath(node);
 613  0
             NodeList nl = (NodeList) xp.evaluate(xpath, node, XPathConstants.NODESET);
 614  0
             List<Node> nodeList = new ArrayList<Node>(nl.getLength());
 615  0
             for (int i = 0; i < nl.getLength(); i++)
 616  
             {
 617  0
                 nodeList.add(nl.item(i));
 618  
             }
 619  0
             return nodeList;
 620  
     }
 621  
 
 622  
 
 623  
 
 624  
     /**
 625  
      * The default namespace context that will read namespaces from the current document if the
 626  
      * Node being processed is a Document
 627  
      */
 628  0
     private static class XPathNamespaceContext implements NamespaceContext
 629  
     {
 630  
         private Document document;
 631  
 
 632  
         public XPathNamespaceContext(Document document)
 633  0
         {
 634  0
             this.document = document;
 635  0
         }
 636  
 
 637  
         public String getNamespaceURI(String prefix)
 638  
         {
 639  0
             if (prefix == null || prefix.equals(""))
 640  
             {
 641  0
                 return document.getDocumentElement().getNamespaceURI();
 642  
             }
 643  
             else
 644  
             {
 645  0
                 return document.lookupNamespaceURI(prefix);
 646  
             }
 647  
         }
 648  
 
 649  
         public String getPrefix(String namespaceURI)
 650  
         {
 651  0
             return document.lookupPrefix(namespaceURI);
 652  
         }
 653  
 
 654  
         public Iterator<String> getPrefixes(String namespaceURI)
 655  
         {
 656  0
             List<String> list = new ArrayList<String>();
 657  0
             list.add(getPrefix(namespaceURI));
 658  0
             return list.iterator();
 659  
         }
 660  
     }
 661  
 }