jaxp/src/com/sun/org/apache/xml/internal/serialize/XMLSerializer.java
changeset 23777 ce87cedb71cf
parent 12457 c348e06f0e82
child 25834 aba3efbf4ec5
equal deleted inserted replaced
23776:e517d680b5cf 23777:ce87cedb71cf
     1 /*
     1 /*
     2  * reserved comment block
     2  * reserved comment block
     3  * DO NOT REMOVE OR ALTER!
     3  * DO NOT REMOVE OR ALTER!
     4  */
     4  */
     5 /*
     5 /*
     6  * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
     6  * Licensed to the Apache Software Foundation (ASF) under one or more
     7  *
     7  * contributor license agreements.  See the NOTICE file distributed with
     8  * Licensed under the Apache License, Version 2.0 (the "License");
     8  * this work for additional information regarding copyright ownership.
     9  * you may not use this file except in compliance with the License.
     9  * The ASF licenses this file to You under the Apache License, Version 2.0
    10  * You may obtain a copy of the License at
    10  * (the "License"); you may not use this file except in compliance with
       
    11  * the License.  You may obtain a copy of the License at
    11  *
    12  *
    12  *      http://www.apache.org/licenses/LICENSE-2.0
    13  *      http://www.apache.org/licenses/LICENSE-2.0
    13  *
    14  *
    14  * Unless required by applicable law or agreed to in writing, software
    15  * Unless required by applicable law or agreed to in writing, software
    15  * distributed under the License is distributed on an "AS IS" BASIS,
    16  * distributed under the License is distributed on an "AS IS" BASIS,
    16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  * See the License for the specific language governing permissions and
    18  * See the License for the specific language governing permissions and
    18  * limitations under the License.
    19  * limitations under the License.
    19  */
    20  */
    20 
       
    21 
       
    22 
    21 
    23 // Sep 14, 2000:
    22 // Sep 14, 2000:
    24 //  Fixed problem with namespace handling. Contributed by
    23 //  Fixed problem with namespace handling. Contributed by
    25 //  David Blondeau <blondeau@intalio.com>
    24 //  David Blondeau <blondeau@intalio.com>
    26 // Sep 14, 2000:
    25 // Sep 14, 2000:
    31 //  Fixed bug in startDocument not calling prepare.
    30 //  Fixed bug in startDocument not calling prepare.
    32 //  Reported by Mikael Staldal <d96-mst-ingen-reklam@d.kth.se>
    31 //  Reported by Mikael Staldal <d96-mst-ingen-reklam@d.kth.se>
    33 // Aug 21, 2000:
    32 // Aug 21, 2000:
    34 //  Added ability to omit DOCTYPE declaration.
    33 //  Added ability to omit DOCTYPE declaration.
    35 
    34 
    36 
       
    37 package com.sun.org.apache.xml.internal.serialize;
    35 package com.sun.org.apache.xml.internal.serialize;
    38 
       
    39 
    36 
    40 import java.io.IOException;
    37 import java.io.IOException;
    41 import java.io.OutputStream;
    38 import java.io.OutputStream;
    42 import java.io.Writer;
    39 import java.io.Writer;
    43 import java.util.Enumeration;
    40 import java.util.Iterator;
       
    41 import java.util.Map;
    44 
    42 
    45 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
    43 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
    46 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
    44 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
    47 import com.sun.org.apache.xerces.internal.util.SymbolTable;
    45 import com.sun.org.apache.xerces.internal.util.SymbolTable;
    48 import com.sun.org.apache.xerces.internal.util.XMLChar;
    46 import com.sun.org.apache.xerces.internal.util.XMLChar;
    49 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
    47 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
    50 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
    48 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
    51 import org.w3c.dom.Attr;
    49 import org.w3c.dom.Attr;
    52 import org.w3c.dom.DOMError;
    50 import org.w3c.dom.DOMError;
       
    51 import org.w3c.dom.Document;
    53 import org.w3c.dom.Element;
    52 import org.w3c.dom.Element;
    54 import org.w3c.dom.NamedNodeMap;
    53 import org.w3c.dom.NamedNodeMap;
    55 import org.w3c.dom.Node;
    54 import org.w3c.dom.Node;
    56 import org.w3c.dom.traversal.NodeFilter;
    55 import org.w3c.dom.traversal.NodeFilter;
    57 import org.xml.sax.AttributeList;
    56 import org.xml.sax.AttributeList;
    69  * as specified in the output format.
    68  * as specified in the output format.
    70  * <p>
    69  * <p>
    71  * The serializer supports both DOM and SAX. SAX serializing is done by firing
    70  * The serializer supports both DOM and SAX. SAX serializing is done by firing
    72  * SAX events and using the serializer as a document handler. DOM serializing is done
    71  * SAX events and using the serializer as a document handler. DOM serializing is done
    73  * by calling {@link #serialize(Document)} or by using DOM Level 3
    72  * by calling {@link #serialize(Document)} or by using DOM Level 3
    74  * {@link org.w3c.dom.ls.DOMSerializer} and
    73  * {@link org.w3c.dom.ls.LSSerializer} and
    75  * serializing with {@link org.w3c.dom.ls.DOMSerializer#write},
    74  * serializing with {@link org.w3c.dom.ls.LSSerializer#write},
    76  * {@link org.w3c.dom.ls.DOMSerializer#writeToString}.
    75  * {@link org.w3c.dom.ls.LSSerializer#writeToString}.
    77  * <p>
    76  * <p>
    78  * If an I/O exception occurs while serializing, the serializer
    77  * If an I/O exception occurs while serializing, the serializer
    79  * will not throw an exception directly, but only throw it
    78  * will not throw an exception directly, but only throw it
    80  * at the end of serializing (either DOM or SAX's {@link
    79  * at the end of serializing (either DOM or SAX's {@link
    81  * org.xml.sax.DocumentHandler#endDocument}.
    80  * org.xml.sax.DocumentHandler#endDocument}.
   193 
   192 
   194 
   193 
   195     /**
   194     /**
   196      * This methods turns on namespace fixup algorithm during
   195      * This methods turns on namespace fixup algorithm during
   197      * DOM serialization.
   196      * DOM serialization.
   198      * @see org.w3c.dom.ls.DOMSerializer
   197      * @see org.w3c.dom.ls.LSSerializer
   199      *
   198      *
   200      * @param namespaces
   199      * @param namespaces
   201      */
   200      */
   202     public void setNamespaces (boolean namespaces){
   201     public void setNamespaces (boolean namespaces){
   203         fNamespaces = namespaces;
   202         fNamespaces = namespaces;
   220         int          i;
   219         int          i;
   221         boolean      preserveSpace;
   220         boolean      preserveSpace;
   222         ElementState state;
   221         ElementState state;
   223         String       name;
   222         String       name;
   224         String       value;
   223         String       value;
   225         boolean      addNSAttr = false;
       
   226 
   224 
   227         if (DEBUG) {
   225         if (DEBUG) {
   228             System.out.println("==>startElement("+namespaceURI+","+localName+
   226             System.out.println("==>startElement("+namespaceURI+","+localName+
   229                                ","+rawName+")");
   227                                ","+rawName+")");
   230         }
   228         }
   275                     throw new SAXException(msg);
   273                     throw new SAXException(msg);
   276                 }
   274                 }
   277                 if (namespaceURI != null && ! namespaceURI.equals( "" )) {
   275                 if (namespaceURI != null && ! namespaceURI.equals( "" )) {
   278                     String prefix;
   276                     String prefix;
   279                     prefix = getPrefix( namespaceURI );
   277                     prefix = getPrefix( namespaceURI );
   280                     if (prefix != null && prefix.length() > 0)
   278                     if (prefix != null && prefix.length() > 0) {
   281                         rawName = prefix + ":" + localName;
   279                         rawName = prefix + ":" + localName;
   282                     else
   280                     }
       
   281                     else {
   283                         rawName = localName;
   282                         rawName = localName;
   284                 } else
   283                     }
       
   284                 }
       
   285                 else {
   285                     rawName = localName;
   286                     rawName = localName;
   286                 addNSAttr = true;
   287                 }
   287             }
   288             }
   288 
   289 
   289             _printer.printText( '<' );
   290             _printer.printText( '<' );
   290             _printer.printText( rawName );
   291             _printer.printText( rawName );
   291             _printer.indent();
   292             _printer.indent();
   332                     }
   333                     }
   333                 }
   334                 }
   334             }
   335             }
   335 
   336 
   336             if (_prefixes != null) {
   337             if (_prefixes != null) {
   337                 Enumeration keys;
   338                 Iterator entries = _prefixes.entrySet().iterator();
   338 
   339                 while (entries.hasNext()) {
   339                 keys = _prefixes.keys();
       
   340                 while (keys.hasMoreElements()) {
       
   341                     _printer.printSpace();
   340                     _printer.printSpace();
   342                     value = (String) keys.nextElement();
   341                     Map.Entry entry = (Map.Entry) entries.next();
   343                     name = (String) _prefixes.get( value );
   342                     value = (String) entry.getKey();
       
   343                     name = (String) entry.getValue();
   344                     if (name.length() == 0) {
   344                     if (name.length() == 0) {
   345                         _printer.printText( "xmlns=\"" );
   345                         _printer.printText( "xmlns=\"" );
   346                         printEscaped( value );
   346                         printEscaped( value );
   347                         _printer.printText( '"' );
   347                         _printer.printText( '"' );
   348                     } else {
   348                     }
       
   349                     else {
   349                         _printer.printText( "xmlns:" );
   350                         _printer.printText( "xmlns:" );
   350                         _printer.printText( name );
   351                         _printer.printText( name );
   351                         _printer.printText( "=\"" );
   352                         _printer.printText( "=\"" );
   352                         printEscaped( value );
   353                         printEscaped( value );
   353                         _printer.printText( '"' );
   354                         _printer.printText( '"' );
   768                             } else {
   769                             } else {
   769                                 // REVISIT: issue error on invalid declarations
   770                                 // REVISIT: issue error on invalid declarations
   770                                 //          xmlns:foo = ""
   771                                 //          xmlns:foo = ""
   771                             }
   772                             }
   772                             continue;
   773                             continue;
   773                         } else { // xmlns
       
   774                             // empty prefix is always bound ("" or some string)
       
   775 
       
   776                             value = fSymbolTable.addSymbol(value);
       
   777                             fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value);
       
   778                             continue;
       
   779                         }
   774                         }
       
   775                         // xmlns --- empty prefix is always bound ("" or some string)
       
   776                         value = fSymbolTable.addSymbol(value);
       
   777                         fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value);
       
   778                         continue;
   780                     }  // end-else: valid declaration
   779                     }  // end-else: valid declaration
   781                 } // end-if: namespace declaration
   780                 } // end-if: namespace declaration
   782             }  // end-for
   781             }  // end-for
   783 
   782 
   784             //-----------------------
   783             //-----------------------
   956                             } else {
   955                             } else {
   957                                 // REVISIT: issue error on invalid declarations
   956                                 // REVISIT: issue error on invalid declarations
   958                                 //          xmlns:foo = ""
   957                                 //          xmlns:foo = ""
   959                             }
   958                             }
   960                             continue;
   959                             continue;
   961                         } else { // xmlns
   960                         }
   962                             // empty prefix is always bound ("" or some string)
   961                         // xmlns --- empty prefix is always bound ("" or some string)
   963 
   962                         uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING);
   964                             uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING);
   963                         localUri= fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING);
   965                             localUri=fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING);
   964                         value = fSymbolTable.addSymbol(value);
   966                             value = fSymbolTable.addSymbol(value);
   965                         if (localUri == null ) {
   967                             if (localUri == null ){
   966                             // declaration was not printed while fixing element namespace binding
   968                                 // declaration was not printed while fixing element namespace binding
   967                             if (fNamespacePrefixes) {
   969                                 if (fNamespacePrefixes) {
   968                                 printNamespaceAttr(XMLSymbols.EMPTY_STRING, value);
   970                                     printNamespaceAttr(XMLSymbols.EMPTY_STRING, value);
       
   971                                 }
       
   972                                 // case 4 does not apply here since attributes can't use
       
   973                                 // default namespace
       
   974                             }
   969                             }
   975                             continue;
   970                             // case 4 does not apply here since attributes can't use
       
   971                             // default namespace
   976                         }
   972                         }
       
   973                         continue;
   977 
   974 
   978                     }
   975                     }
   979                     uri = fSymbolTable.addSymbol(uri);
   976                     uri = fSymbolTable.addSymbol(uri);
   980 
   977 
   981                     // find if for this prefix a URI was already declared
   978                     // find if for this prefix a URI was already declared
  1193     throws SAXException
  1190     throws SAXException
  1194     {
  1191     {
  1195         AttributesImpl attrsOnly;
  1192         AttributesImpl attrsOnly;
  1196         String         rawName;
  1193         String         rawName;
  1197         int            i;
  1194         int            i;
  1198         int            indexColon;
       
  1199         String         prefix;
       
  1200         int            length;
  1195         int            length;
  1201 
  1196 
  1202         if (attrs == null) {
  1197         if (attrs == null) {
  1203             return null;
  1198             return null;
  1204         }
  1199         }
  1231         int length = source.length();
  1226         int length = source.length();
  1232         for (int i = 0; i < length; ++i) {
  1227         for (int i = 0; i < length; ++i) {
  1233             int ch = source.charAt(i);
  1228             int ch = source.charAt(i);
  1234             if (!XMLChar.isValid(ch)) {
  1229             if (!XMLChar.isValid(ch)) {
  1235                 if (++i < length) {
  1230                 if (++i < length) {
  1236                     surrogates(ch, source.charAt(i));
  1231                     surrogates(ch, source.charAt(i), false);
  1237                 } else {
  1232                 } else {
  1238                     fatalError("The character '" + (char) ch + "' is an invalid XML character");
  1233                     fatalError("The character '" + (char) ch + "' is an invalid XML character");
  1239                 }
  1234                 }
  1240                 continue;
  1235                 continue;
  1241             }
  1236             }
  1289             for ( index = 0 ; index < length ; ++index ) {
  1284             for ( index = 0 ; index < length ; ++index ) {
  1290                 ch = text.charAt( index );
  1285                 ch = text.charAt( index );
  1291                 if (!XMLChar.isValid(ch)) {
  1286                 if (!XMLChar.isValid(ch)) {
  1292                     // check if it is surrogate
  1287                     // check if it is surrogate
  1293                     if (++index <length) {
  1288                     if (++index <length) {
  1294                         surrogates(ch, text.charAt(index));
  1289                         surrogates(ch, text.charAt(index), true);
  1295                     } else {
  1290                     } else {
  1296                         fatalError("The character '"+(char)ch+"' is an invalid XML character");
  1291                         fatalError("The character '"+ch+"' is an invalid XML character");
  1297                     }
  1292                     }
  1298                     continue;
  1293                     continue;
  1299                 }
  1294                 }
  1300                 if ( unescaped ) {
  1295                 if ( unescaped ) {
  1301                     _printer.printText( ch );
  1296                     _printer.printText( ch );
  1302                 } else
  1297                 } else {
  1303                     printXMLChar( ch );
  1298                     printXMLChar( ch );
       
  1299                 }
  1304             }
  1300             }
  1305         } else {
  1301         } else {
  1306             // Not preserving spaces: print one part at a time, and
  1302             // Not preserving spaces: print one part at a time, and
  1307             // use spaces between parts to break them into different
  1303             // use spaces between parts to break them into different
  1308             // lines. Spaces at beginning of line will be stripped
  1304             // lines. Spaces at beginning of line will be stripped
  1311             for ( index = 0 ; index < length ; ++index ) {
  1307             for ( index = 0 ; index < length ; ++index ) {
  1312                 ch = text.charAt( index );
  1308                 ch = text.charAt( index );
  1313                 if (!XMLChar.isValid(ch)) {
  1309                 if (!XMLChar.isValid(ch)) {
  1314                     // check if it is surrogate
  1310                     // check if it is surrogate
  1315                     if (++index <length) {
  1311                     if (++index <length) {
  1316                         surrogates(ch, text.charAt(index));
  1312                         surrogates(ch, text.charAt(index), true);
  1317                     } else {
  1313                     } else {
  1318                         fatalError("The character '"+(char)ch+"' is an invalid XML character");
  1314                         fatalError("The character '"+ch+"' is an invalid XML character");
  1319                     }
  1315                     }
  1320                     continue;
  1316                     continue;
  1321                 }
  1317                 }
  1322 
  1318 
  1323                                 if ( unescaped )
  1319                 if ( unescaped ) {
  1324                     _printer.printText( ch );
  1320                     _printer.printText( ch );
  1325                 else
  1321                 } else {
  1326                     printXMLChar( ch);
  1322                     printXMLChar( ch );
       
  1323                 }
  1327             }
  1324             }
  1328         }
  1325         }
  1329     }
  1326     }
  1330 
  1327 
  1331 
  1328 
  1332 
  1329 
  1333     protected void printText( char[] chars, int start, int length,
  1330     protected void printText( char[] chars, int start, int length,
  1334                               boolean preserveSpace, boolean unescaped ) throws IOException {
  1331                               boolean preserveSpace, boolean unescaped ) throws IOException {
  1335         int index;
       
  1336         char ch;
       
  1337 
  1332 
  1338         if ( preserveSpace ) {
  1333         if ( preserveSpace ) {
  1339             // Preserving spaces: the text must print exactly as it is,
  1334             // Preserving spaces: the text must print exactly as it is,
  1340             // without breaking when spaces appear in the text and without
  1335             // without breaking when spaces appear in the text and without
  1341             // consolidating spaces. If a line terminator is used, a line
  1336             // consolidating spaces. If a line terminator is used, a line
  1342             // break will occur.
  1337             // break will occur.
  1343             while ( length-- > 0 ) {
  1338             while ( length-- > 0 ) {
  1344                 ch = chars[start++];
  1339                 char ch = chars[start++];
  1345                 if (!XMLChar.isValid(ch)) {
  1340                 if (!XMLChar.isValid(ch)) {
  1346                     // check if it is surrogate
  1341                     // check if it is surrogate
  1347                     if ( length-- > 0 ) {
  1342                     if ( length-- > 0 ) {
  1348                         surrogates(ch, chars[start++]);
  1343                         surrogates(ch, chars[start++], true);
  1349                     } else {
  1344                     } else {
  1350                         fatalError("The character '"+(char)ch+"' is an invalid XML character");
  1345                         fatalError("The character '"+ch+"' is an invalid XML character");
  1351                     }
  1346                     }
  1352                     continue;
  1347                     continue;
  1353                 }
  1348                 }
  1354                 if ( unescaped )
  1349                 if ( unescaped )
  1355                     _printer.printText( ch );
  1350                     _printer.printText( ch );
  1361             // use spaces between parts to break them into different
  1356             // use spaces between parts to break them into different
  1362             // lines. Spaces at beginning of line will be stripped
  1357             // lines. Spaces at beginning of line will be stripped
  1363             // by printing mechanism. Line terminator is treated
  1358             // by printing mechanism. Line terminator is treated
  1364             // no different than other text part.
  1359             // no different than other text part.
  1365             while ( length-- > 0 ) {
  1360             while ( length-- > 0 ) {
  1366                 ch = chars[start++];
  1361                 char ch = chars[start++];
  1367                 if (!XMLChar.isValid(ch)) {
  1362                 if (!XMLChar.isValid(ch)) {
  1368                     // check if it is surrogate
  1363                     // check if it is surrogate
  1369                     if ( length-- > 0 ) {
  1364                     if ( length-- > 0 ) {
  1370                         surrogates(ch, chars[start++]);
  1365                         surrogates(ch, chars[start++], true);
  1371                     } else {
  1366                     } else {
  1372                         fatalError("The character '"+(char)ch+"' is an invalid XML character");
  1367                         fatalError("The character '"+ch+"' is an invalid XML character");
  1373                     }
  1368                     }
  1374                     continue;
  1369                     continue;
  1375                 }
  1370                 }
  1376                 if ( unescaped )
  1371                 if ( unescaped )
  1377                     _printer.printText( ch );
  1372                     _printer.printText( ch );