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}. |
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 |
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 ); |