View Javadoc

    1   package org.codehaus.xfire.util;
    2
    3   import java.io.InputStream;
    4   import java.io.OutputStream;
    5   import java.io.Reader;
    6
    7   import javax.xml.parsers.DocumentBuilder;
    8   import javax.xml.stream.XMLInputFactory;
    9   import javax.xml.stream.XMLOutputFactory;
    10  import javax.xml.stream.XMLStreamConstants;
    11  import javax.xml.stream.XMLStreamException;
    12  import javax.xml.stream.XMLStreamReader;
    13  import javax.xml.stream.XMLStreamWriter;
    14
    15  import org.codehaus.xfire.XFireRuntimeException;
    16  import org.codehaus.xfire.util.stax.DepthXMLStreamReader;
    17  import org.w3c.dom.Attr;
    18  import org.w3c.dom.Document;
    19  import org.w3c.dom.Element;
    20  import org.w3c.dom.NamedNodeMap;
    21  import org.w3c.dom.Node;
    22  import org.w3c.dom.NodeList;
    23
    24  /***
    25   * Common StAX utilities.
    26   *
    27   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
    28   * @since Oct 26, 2004
    29   */
    30  public class STAXUtils
    31  {
    32      private static final String XML_NS = "http://www.w3.org/2000/xmlns/";
    33
    34      /***
    35       * Returns true if currently at the start of an element, otherwise move forwards to the next
    36       * element start and return true, otherwise false is returned if the end of the stream is reached.
    37       */
    38      public static boolean skipToStartOfElement(XMLStreamReader in)
    39          throws XMLStreamException
    40      {
    41          for (int code = in.getEventType(); code != XMLStreamReader.END_DOCUMENT; code = in.next())
    42          {
    43              if (code == XMLStreamReader.START_ELEMENT)
    44              {
    45                  return true;
    46              }
    47          }
    48          return false;
    49      }
    50
    51      public static boolean toNextElement(DepthXMLStreamReader dr)
    52      {
    53          if (dr.getEventType() == XMLStreamReader.START_ELEMENT)
    54              return true;
    55
    56          if (dr.getEventType() == XMLStreamReader.END_ELEMENT)
    57              return false;
    58
    59          try
    60          {
    61              int depth = dr.getDepth();
    62
    63              for (int event = dr.getEventType(); dr.getDepth() >= depth; event = dr.next())
    64              {
    65                  if (event == XMLStreamReader.START_ELEMENT && dr.getDepth() == depth + 1)
    66                  {
    67                      return true;
    68                  }
    69                  else if (event == XMLStreamReader.END_ELEMENT)
    70                  {
    71                      depth--;
    72                  }
    73              }
    74
    75              return false;
    76          }
    77          catch (XMLStreamException e)
    78          {
    79              throw new XFireRuntimeException("Couldn't parse stream.", e);
    80          }
    81      }
    82
    83      public static boolean skipToStartOfElement(DepthXMLStreamReader in)
    84          throws XMLStreamException
    85      {
    86          for (int code = in.getEventType(); code != XMLStreamReader.END_DOCUMENT; code = in.next())
    87          {
    88              if (code == XMLStreamReader.START_ELEMENT)
    89              {
    90                  return true;
    91              }
    92          }
    93          return false;
    94      }
    95
    96      /***
    97       * Copies the reader to the writer.  The start and end document
    98       * methods must be handled on the writer manually.
    99       *
    100      * TODO: if the namespace on the reader has been declared previously
    101      * to where we are in the stream, this probably won't work.
    102      *
    103      * @param reader
    104      * @param writer
    105      * @throws XMLStreamException
    106      */
    107     public static void copy( XMLStreamReader reader, XMLStreamWriter writer )
    108         throws XMLStreamException
    109     {
    110         int read = 0; // number of elements read in
    111         int event = reader.getEventType();
    112
    113         while ( reader.hasNext() )
    114         {
    115             switch( event )
    116             {
    117                 case XMLStreamConstants.START_ELEMENT:
    118                     read++;
    119                     writeStartElement( reader, writer );
    120                     break;
    121                 case XMLStreamConstants.END_ELEMENT:
    122                     writer.writeEndElement();
    123                     read--;
    124                     if ( read <= 0 )
    125                         return;
    126                     break;
    127                 case XMLStreamConstants.CHARACTERS:
    128                     writer.writeCharacters( reader.getText() );
    129                     break;
    130                 case XMLStreamConstants.START_DOCUMENT:
    131                 case XMLStreamConstants.END_DOCUMENT:
    132                 case XMLStreamConstants.ATTRIBUTE:
    133                 case XMLStreamConstants.NAMESPACE:
    134                     break;
    135                 default:
    136                     break;
    137             }
    138             event = reader.next();
    139         }
    140     }
    141
    142     private static void writeStartElement(XMLStreamReader reader, XMLStreamWriter writer)
    143         throws XMLStreamException
    144     {
    145         String local = reader.getLocalName();
    146         String uri = reader.getNamespaceURI();
    147         String prefix = reader.getPrefix();
    148         if (prefix == null)
    149         {
    150             prefix = "";
    151         }
    152
    153         String boundPrefix = writer.getPrefix(uri);
    154         boolean writeElementNS = false;
    155         if ( boundPrefix == null || !prefix.equals(boundPrefix) )
    156         {
    157             writeElementNS = true;
    158         }
    159
    160         // Write out the element name
    161         if (uri != null)
    162         {
    163             if (prefix.length() == 0)
    164             {
    165                 writer.writeStartElement(local);
    166                 writer.setDefaultNamespace(uri);
    167             }
    168             else
    169             {
    170                 writer.writeStartElement(prefix, local, uri);
    171                 writer.setPrefix(prefix, uri);
    172             }
    173         }
    174         else
    175         {
    176             writer.writeStartElement( reader.getLocalName() );
    177         }
    178
    179         // Write out the namespaces
    180         for ( int i = 0; i < reader.getNamespaceCount(); i++ )
    181         {
    182             String nsURI = reader.getNamespaceURI(i);
    183             String nsPrefix = reader.getNamespacePrefix(i);
    184             if (nsPrefix == null) nsPrefix = "";
    185
    186             if ( nsPrefix.length() ==  0 )
    187             {
    188                 writer.writeDefaultNamespace(nsURI);
    189             }
    190             else
    191             {
    192                 writer.writeNamespace(nsPrefix, nsURI);
    193             }
    194
    195             if (nsURI.equals(uri) && nsPrefix.equals(prefix))
    196             {
    197                 writeElementNS = false;
    198             }
    199         }
    200
    201         // Check if the namespace still needs to be written.
    202         // We need this check because namespace writing works
    203         // different on Woodstox and the RI.
    204         if (writeElementNS)
    205         {
    206             if ( prefix == null || prefix.length() ==  0 )
    207             {
    208                 writer.writeDefaultNamespace(uri);
    209             }
    210             else
    211             {
    212                 writer.writeNamespace(prefix, uri);
    213             }
    214         }
    215
    216         // Write out attributes
    217         for ( int i = 0; i < reader.getAttributeCount(); i++ )
    218         {
    219             String ns = reader.getAttributeNamespace(i);
    220             String nsPrefix = reader.getAttributePrefix(i);
    221             if ( ns == null || ns.length() == 0 )
    222             {
    223                 writer.writeAttribute(
    224                         reader.getAttributeLocalName(i),
    225                         reader.getAttributeValue(i));
    226             }
    227             else if (nsPrefix == null || nsPrefix.length() == 0)
    228             {
    229                 writer.writeAttribute(
    230                     reader.getAttributeNamespace(i),
    231                     reader.getAttributeLocalName(i),
    232                     reader.getAttributeValue(i));
    233             }
    234             else
    235             {
    236                 writer.writeAttribute(reader.getAttributePrefix(i),
    237                                       reader.getAttributeNamespace(i),
    238                                       reader.getAttributeLocalName(i),
    239                                       reader.getAttributeValue(i));
    240             }
    241
    242
    243         }
    244     }
    245
    246     /***
    247      * Writes an Element to an XMLStreamWriter.  The writer must already
    248      * have started the doucment (via writeStartDocument()). Also, this probably
    249      * won't work with just a fragment of a document. The Element should be
    250      * the root element of the document.
    251      *
    252      * @param e
    253      * @param writer
    254      * @throws XMLStreamException
    255      */
    256     public static void writeElement( Element e, XMLStreamWriter writer )
    257         throws XMLStreamException
    258     {
    259         String prefix = e.getPrefix();
    260         String ns = e.getNamespaceURI();
    261         String localName = e.getLocalName();
    262
    263         if ( prefix == null )
    264         {
    265             if ( ns == null )
    266             {
    267                 writer.writeStartElement( localName );
    268             }
    269             else
    270             {
    271                 prefix = "";
    272                 writer.setDefaultNamespace(ns);
    273                 writer.writeStartElement( ns, localName );
    274
    275                 String curUri = writer.getNamespaceContext().getNamespaceURI(prefix);
    276                 if ( curUri == null || curUri.length() != ns.length() )
    277                 {
    278                     writer.writeDefaultNamespace(ns);
    279                 }
    280             }
    281         }
    282         else
    283         {
    284             writer.writeStartElement(prefix, localName, ns);
    285
    286             String curUri = writer.getNamespaceContext().getNamespaceURI(prefix);
    287             if ( curUri == null || curUri.length() != ns.length() || !curUri.equals(ns) )
    288             {
    289                 writer.writeNamespace(prefix, ns);
    290             }
    291         }
    292
    293         NamedNodeMap attrs = e.getAttributes();
    294         for ( int i = 0; i < attrs.getLength(); i++ )
    295         {
    296             Node attr = attrs.item(i);
    297
    298             String attrPrefix = writer.getNamespaceContext().getPrefix(attr.getNamespaceURI());
    299             if ( attrPrefix == null )
    300             {
    301                 writer.writeAttribute(attr.getNamespaceURI(), attr.getNodeName(), attr.getNodeValue());
    302             }
    303             else
    304             {
    305                 writer.writeAttribute(attrPrefix, attr.getNamespaceURI(), attr.getNodeName(), attr.getNodeValue());
    306             }
    307         }
    308
    309         String value = DOMUtils.getContent(e);
    310
    311         if ( value != null && value.length() > 0)
    312             writer.writeCharacters( value );
    313
    314         NodeList nodes = e.getChildNodes();
    315         for ( int i = 0; i < nodes.getLength(); i++ )
    316         {
    317             Node n = nodes.item(i);
    318             if ( n instanceof Element )
    319             {
    320                 writeElement((Element)n, writer);
    321             }
    322         }
    323
    324         writer.writeEndElement();
    325     }
    326
    327     /***
    328      * @param e
    329      * @return
    330      */
    331     private static Element getNamespaceDeclarer(Element e)
    332     {
    333         while( true )
    334         {
    335             Node n = e.getParentNode();
    336             if ( n.equals(e) )
    337                 return null;
    338             if ( n.getNamespaceURI() != null )
    339                 return (Element) n;
    340         }
    341     }
    342
    343     public static Document read(DocumentBuilder builder, XMLStreamReader reader)
    344         throws XMLStreamException
    345     {
    346         Document doc = builder.newDocument();
    347
    348         readDocElements(doc, reader);
    349
    350         return doc;
    351     }
    352
    353     /***
    354      * @param parent
    355      * @return
    356      */
    357     private static Document getDocument(Node parent)
    358     {
    359         return (parent instanceof Document) ? (Document) parent : parent.getOwnerDocument();
    360     }
    361
    362     /***
    363      * @param parent
    364      * @param reader
    365      * @return
    366      * @throws XMLStreamException
    367      */
    368     private static Element startElement(Node parent, XMLStreamReader reader)
    369         throws XMLStreamException
    370     {
    371         Document doc = getDocument(parent);
    372
    373         Element e = doc.createElementNS(reader.getNamespaceURI(), reader.getLocalName());
    374         e.setPrefix(reader.getPrefix());
    375
    376         declareNamespaces(reader, e);
    377
    378         for (int i = 0; i < reader.getAttributeCount(); i++)
    379         {
    380             Attr attr = doc.createAttributeNS(reader.getAttributeNamespace(i), reader
    381                     .getAttributeLocalName(i));
    382             attr.setValue(reader.getAttributeValue(i));
    383             e.setAttributeNode(attr);
    384         }
    385
    386         parent.appendChild(e);
    387
    388         reader.next();
    389
    390         readDocElements(e, reader);
    391
    392         return e;
    393     }
    394
    395     /***
    396      * @param parent
    397      * @param reader
    398      * @throws XMLStreamException
    399      */
    400     public static void readDocElements(Node parent, XMLStreamReader reader)
    401         throws XMLStreamException
    402     {
    403         Document doc = getDocument(parent);
    404
    405         int event = reader.getEventType();
    406         while (reader.hasNext())
    407         {
    408             switch (event)
    409             {
    410             case XMLStreamConstants.START_ELEMENT:
    411                 startElement(parent, reader);
    412
    413                 if (parent instanceof Document)
    414                 {
    415                     if (reader.hasNext()) reader.next();
    416                     return;
    417                 }
    418
    419                 break;
    420             case XMLStreamConstants.END_ELEMENT:
    421                 return;
    422             case XMLStreamConstants.CHARACTERS:
    423                 if (parent != null)
    424                 {
    425                     parent.appendChild(doc.createTextNode(reader.getText()));
    426                 }
    427
    428                 break;
    429             default:
    430                 break;
    431             }
    432
    433             if (reader.hasNext())
    434             {
    435                 event = reader.next();
    436             }
    437         }
    438     }
    439
    440     private static void declareNamespaces(XMLStreamReader reader, Element node)
    441     {
    442         for (int i = 0; i < reader.getNamespaceCount(); i++)
    443         {
    444             String uri = reader.getNamespaceURI(i);
    445             String prefix = reader.getNamespacePrefix(i);
    446             // TODO : i'm not sure about skiping parent namespaces, so i comment it for a while
    447             if (prefix != null && prefix.length()>0 /* && !uri.equals(node.getNamespaceURI()) */)
    448             {
    449                 node.setAttributeNS(XML_NS,"xmlns:"+prefix, uri);
    450             }else{
    451                 if( uri != null && uri.length()>0){
    452                     node.setAttribute("xmlns",uri);
    453                 }
    454             }
    455         }
    456     }
    457
    458     public static XMLStreamWriter createXMLStreamWriter(OutputStream out, String encoding)
    459     {
    460         XMLOutputFactory factory = XMLOutputFactory.newInstance();
    461
    462         if (encoding == null) encoding = "UTF-8";
    463
    464         try
    465         {
    466             XMLStreamWriter writer = factory.createXMLStreamWriter(out, encoding);
    467
    468             return writer;
    469         }
    470         catch (XMLStreamException e)
    471         {
    472             throw new XFireRuntimeException("Couldn't parse stream.", e);
    473         }
    474     }
    475
    476     public static XMLStreamReader createXMLStreamReader(InputStream in, String encoding)
    477     {
    478         XMLInputFactory factory = XMLInputFactory.newInstance();
    479
    480         if (encoding == null) encoding = "UTF-8";
    481
    482         try
    483         {
    484             return factory.createXMLStreamReader(in, encoding);
    485         }
    486         catch (XMLStreamException e)
    487         {
    488             throw new XFireRuntimeException("Couldn't parse stream.", e);
    489         }
    490     }
    491
    492     public static XMLStreamReader createXMLStreamReader(Reader reader)
    493     {
    494         XMLInputFactory factory = XMLInputFactory.newInstance();
    495
    496         try
    497         {
    498             return factory.createXMLStreamReader(reader);
    499         }
    500         catch (XMLStreamException e)
    501         {
    502             throw new XFireRuntimeException("Couldn't parse stream.", e);
    503         }
    504     }
    505 }