You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by el...@apache.org on 2002/01/12 01:10:52 UTC
cvs commit: xml-xerces/java/src/org/apache/xml/serialize BaseMarkupSerializer.java XMLSerializer.java
elena 02/01/11 16:10:52
Modified: java/src/org/apache/xerces/util NamespaceSupport.java
java/src/org/apache/xml/serialize BaseMarkupSerializer.java
XMLSerializer.java
Log:
Implemented namespace fixup during serialization of DOM tree.
Revision Changes Path
1.6 +33 -1 xml-xerces/java/src/org/apache/xerces/util/NamespaceSupport.java
Index: NamespaceSupport.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/util/NamespaceSupport.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- NamespaceSupport.java 10 Jan 2002 06:34:23 -0000 1.5
+++ NamespaceSupport.java 12 Jan 2002 00:10:51 -0000 1.6
@@ -67,7 +67,7 @@
*
* @author Andy Clark, IBM
*
- * @version $Id: NamespaceSupport.java,v 1.5 2002/01/10 06:34:23 twl Exp $
+ * @version $Id: NamespaceSupport.java,v 1.6 2002/01/12 00:10:51 elena Exp $
*/
public class NamespaceSupport
implements NamespaceContext {
@@ -273,6 +273,7 @@
// bind prefix to uri in current context
fNamespace[fNamespaceSize++] = prefix;
fNamespace[fNamespaceSize++] = uri;
+
return true;
} // declarePrefix(String,String):boolean
@@ -304,6 +305,36 @@
} // getURI(String):String
+
+
+ /**
+ * Look up a namespace URI and get one of the mapped prefix.
+ * <p>
+ * This method looks up the namespace URI in the current context.
+ *
+ * @param uri The namespace URI to look up.
+ *
+ * @return one of the associated prefixes, or null if the uri
+ * does not map to any prefix.
+ *
+ * @see #getPrefix
+ * @see #getPrefixes
+ */
+ public String getPrefix(String uri) {
+
+ // find uri in current context
+ for (int i = fNamespaceSize; i > 0; i -= 2) {
+ if (fNamespace[i - 1] == uri) {
+ return fNamespace[i - 2];
+ }
+ }
+
+ // uri not found
+ return null;
+
+ } // getURI(String):String
+
+
/**
* Return a count of all prefixes currently declared, including
* the default prefix if bound.
@@ -442,5 +473,6 @@
} // getParentContext():NamespaceContext
} // class Context
+
} // class NamespaceSupport
1.31 +24 -11 xml-xerces/java/src/org/apache/xml/serialize/BaseMarkupSerializer.java
Index: BaseMarkupSerializer.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xml/serialize/BaseMarkupSerializer.java,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- BaseMarkupSerializer.java 3 Dec 2001 21:13:09 -0000 1.30
+++ BaseMarkupSerializer.java 12 Jan 2002 00:10:52 -0000 1.31
@@ -149,7 +149,7 @@
* another element.
*
*
- * @version $Revision: 1.30 $ $Date: 2001/12/03 21:13:09 $
+ * @version $Revision: 1.31 $ $Date: 2002/01/12 00:10:52 $
* @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
* @author <a href="mailto:rahul.srivastava@sun.com">Rahul Srivastava</a>
* @author Elena Litani, IBM
@@ -417,6 +417,7 @@
public void serialize( Element elem )
throws IOException
{
+ reset();
prepare();
serializeNode( elem );
_printer.flush();
@@ -437,6 +438,7 @@
public void serialize( DocumentFragment frag )
throws IOException
{
+ reset();
prepare();
serializeNode( frag );
_printer.flush();
@@ -457,6 +459,7 @@
public void serialize( Document doc )
throws IOException
{
+ reset();
prepare();
serializeNode( doc );
serializePreRoot();
@@ -1211,11 +1214,8 @@
if (index >=0 && !((Boolean)fFeatures.get("split-cdata-sections")).booleanValue()) {
// issue fatal error
if (fDOMErrorHandler != null) {
- fDOMError.reset();
- fDOMError.setMessage("The character sequence \"]]>\" must not appear in content"+
- " unless used to mark the end of a CDATA section.");
- fDOMError.setSeverity(DOMError.SEVERITY_FATAL_ERROR);
- fDOMError.setLocator(new DOMLocatorImpl(-1, -1, -1, fCurrentNode, null));
+ modifyDOMError("The character sequence \"]]>\" must not appear in content"+
+ " unless used to mark the end of a CDATA section.", DOMError.SEVERITY_FATAL_ERROR);
boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
// Should we always terminate the serialization?
// otherwise should we split CDATA section..?
@@ -1227,11 +1227,9 @@
else if (index >=0 && ((Boolean)fFeatures.get("split-cdata-sections")).booleanValue()) {
// issue warning
if (fDOMErrorHandler != null) {
- fDOMError.reset();
- fDOMError.setMessage("Spliting a CDATA section containing the CDATA section termination marker ']]>' ");
- fDOMError.setSeverity(DOMError.SEVERITY_WARNING);
- fDOMError.setLocator(new DOMLocatorImpl(-1, -1, -1, fCurrentNode, null));
- fDOMErrorHandler.handleError(fDOMError);
+ modifyDOMError("Spliting a CDATA section containing the CDATA section termination marker ']]>' ",
+ DOMError.SEVERITY_WARNING);
+ fDOMErrorHandler.handleError(fDOMError);
}
}
@@ -1618,5 +1616,20 @@
return null;
}
+ /**
+ * The method modifies global DOM error object
+ *
+ * @param message
+ * @param severity
+ * @return
+ */
+ protected DOMError modifyDOMError(String message, short severity){
+ fDOMError.reset();
+ fDOMError.setMessage(message);
+ fDOMError.setSeverity(severity);
+ fDOMError.setLocator(new DOMLocatorImpl(-1, -1, -1, fCurrentNode, null));
+ return fDOMError;
+
+ }
}
1.27 +664 -285 xml-xerces/java/src/org/apache/xml/serialize/XMLSerializer.java
Index: XMLSerializer.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xml/serialize/XMLSerializer.java,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- XMLSerializer.java 3 Dec 2001 21:13:09 -0000 1.26
+++ XMLSerializer.java 12 Jan 2002 00:10:52 -0000 1.27
@@ -90,8 +90,13 @@
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import org.apache.xerces.dom3.DOMErrorHandler;
+import org.apache.xerces.dom3.DOMError;
import org.apache.xerces.dom3.ls.DOMWriter;
import org.apache.xerces.dom3.DOMErrorHandler;
+import org.apache.xerces.util.SymbolTable;
+import org.apache.xerces.util.NamespaceSupport;
+import org.apache.xerces.xni.NamespaceContext;
/**
* Implements an XML serializer supporting both DOM and SAX pretty
@@ -118,16 +123,45 @@
* spaces at beginning of line will be stripped.
*
*
- * @version $Revision: 1.26 $ $Date: 2001/12/03 21:13:09 $
+ * @version $Revision: 1.27 $ $Date: 2002/01/12 00:10:52 $
* @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
* @author <a href="mailto:rahul.srivastava@sun.com">Rahul Srivastava</a>
+ * @author Elena Litani, IBM
* @see Serializer
*/
public class XMLSerializer
- extends BaseMarkupSerializer
- implements DOMWriter
-{
+extends BaseMarkupSerializer
+implements DOMWriter {
+
+ //
+ // constants
+ //
+
+ protected static final boolean DEBUG = false;
+
+ //
+ // data
+ //
+
+ protected static final NamespaceSupport fNamespaceSupport = new NamespaceSupport();
+ protected static final SymbolTable fSymbolTable = new SymbolTable();
+ protected String fEmptySymbol;
+ protected String fXmlSymbol;
+ protected String fXmlnsSymbol;
+ // is node dom level 1 node?
+ protected boolean fDOML1 = false;
+ // serialized attributes list
+ int[] fSerializedAttributes = new int[2];
+ // local declarations
+ int[] fLocalNSDecls = new int[2];
+ int fLocalNSCount = 0;
+ int fSerializedCount = 0;
+
+ // counter for new prefix names
+ protected int fNamespaceCounter = 1;
+
+ private boolean fPreserveSpace;
private String fEncoding;
private String fLastEncoding;
@@ -137,8 +171,7 @@
* calling {@link #setOutputCharStream} or {@link #setOutputByteStream}
* first.
*/
- public XMLSerializer()
- {
+ public XMLSerializer() {
super( new OutputFormat( Method.XML, null, false ) );
fFeatures = new Hashtable();
initFeatures();
@@ -150,8 +183,7 @@
* calling {@link #setOutputCharStream} or {@link #setOutputByteStream}
* first.
*/
- public XMLSerializer( OutputFormat format )
- {
+ public XMLSerializer( OutputFormat format ) {
super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
_format.setMethod( Method.XML );
fFeatures = new Hashtable();
@@ -167,8 +199,7 @@
* @param writer The writer to use
* @param format The output format to use, null for the default
*/
- public XMLSerializer( Writer writer, OutputFormat format )
- {
+ public XMLSerializer( Writer writer, OutputFormat format ) {
super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
_format.setMethod( Method.XML );
setOutputCharStream( writer );
@@ -185,8 +216,7 @@
* @param output The output stream to use
* @param format The output format to use, null for the default
*/
- public XMLSerializer( OutputStream output, OutputFormat format )
- {
+ public XMLSerializer( OutputStream output, OutputFormat format ) {
super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
_format.setMethod( Method.XML );
setOutputByteStream( output );
@@ -195,8 +225,7 @@
}
- public void setOutputFormat( OutputFormat format )
- {
+ public void setOutputFormat( OutputFormat format ) {
super.setOutputFormat( format != null ? format : new OutputFormat( Method.XML, null, false ) );
}
@@ -208,7 +237,7 @@
public void startElement( String namespaceURI, String localName,
String rawName, Attributes attrs )
- throws SAXException
+ throws SAXException
{
int i;
boolean preserveSpace;
@@ -218,136 +247,139 @@
boolean addNSAttr = false;
try {
- if ( _printer == null )
- throw new IllegalStateException( "SER002 No writer supplied for serializer" );
+ if (_printer == null)
+ throw new IllegalStateException( "SER002 No writer supplied for serializer" );
- state = getElementState();
- if ( isDocumentState() ) {
- // If this is the root element handle it differently.
- // If the first root element in the document, serialize
- // the document's DOCTYPE. Space preserving defaults
- // to that of the output format.
- if ( ! _started )
+ state = getElementState();
+ if (isDocumentState()) {
+ // If this is the root element handle it differently.
+ // If the first root element in the document, serialize
+ // the document's DOCTYPE. Space preserving defaults
+ // to that of the output format.
+ if (! _started)
startDocument( ( localName == null || localName.length() == 0 ) ? rawName : localName );
- } else {
- // For any other element, if first in parent, then
- // close parent's opening tag and use the parnet's
- // space preserving.
- if ( state.empty )
- _printer.printText( '>' );
- // Must leave CData section first
- if ( state.inCData )
- {
- _printer.printText( "]]>" );
- state.inCData = false;
}
- // Indent this element on a new line if the first
- // content of the parent element or immediately
- // following an element or a comment
- if ( _indenting && ! state.preserveSpace &&
- ( state.empty || state.afterElement || state.afterComment) )
- _printer.breakLine();
- }
- preserveSpace = state.preserveSpace;
+ else {
+ // For any other element, if first in parent, then
+ // close parent's opening tag and use the parnet's
+ // space preserving.
+ if (state.empty)
+ _printer.printText( '>' );
+ // Must leave CData section first
+ if (state.inCData) {
+ _printer.printText( "]]>" );
+ state.inCData = false;
+ }
+ // Indent this element on a new line if the first
+ // content of the parent element or immediately
+ // following an element or a comment
+ if (_indenting && ! state.preserveSpace &&
+ ( state.empty || state.afterElement || state.afterComment))
+ _printer.breakLine();
+ }
+ preserveSpace = state.preserveSpace;
//We remove the namespaces from the attributes list so that they will
//be in _prefixes
attrs = extractNamespaces(attrs);
- // Do not change the current element state yet.
- // This only happens in endElement().
- if ( rawName == null || rawName.length() == 0 ) {
- if ( localName == null )
+ // Do not change the current element state yet.
+ // This only happens in endElement().
+ if (rawName == null || rawName.length() == 0) {
+ if (localName == null)
throw new SAXException( "No rawName and localName is null" );
- if ( namespaceURI != null && ! namespaceURI.equals( "" ) ) {
- String prefix;
- prefix = getPrefix( namespaceURI );
- if ( prefix != null && prefix.length() > 0 )
- rawName = prefix + ":" + localName;
+ if (namespaceURI != null && ! namespaceURI.equals( "" )) {
+ String prefix;
+ prefix = getPrefix( namespaceURI );
+ if (prefix != null && prefix.length() > 0)
+ rawName = prefix + ":" + localName;
else
rawName = localName;
- } else
+ }
+ else
rawName = localName;
- addNSAttr = true;
- }
-
- _printer.printText( '<' );
- _printer.printText( rawName );
- _printer.indent();
-
- // For each attribute print it's name and value as one part,
- // separated with a space so the element can be broken on
- // multiple lines.
- if ( attrs != null ) {
- for ( i = 0 ; i < attrs.getLength() ; ++i ) {
- _printer.printSpace();
+ addNSAttr = true;
+ }
- name = attrs.getQName( i );
- if ( name != null && name.length() == 0 ) {
- String prefix;
- String attrURI;
+ _printer.printText( '<' );
+ _printer.printText( rawName );
+ _printer.indent();
+
+ // For each attribute print it's name and value as one part,
+ // separated with a space so the element can be broken on
+ // multiple lines.
+ if (attrs != null) {
+ for (i = 0 ; i < attrs.getLength() ; ++i) {
+ _printer.printSpace();
- name = attrs.getLocalName( i );
- attrURI = attrs.getURI( i );
- if ( ( attrURI != null && attrURI.length() != 0 ) &&
- ( namespaceURI == null || namespaceURI.length() == 0 ||
- ! attrURI.equals( namespaceURI ) ) ) {
- prefix = getPrefix( attrURI );
- if ( prefix != null && prefix.length() > 0 )
- name = prefix + ":" + name;
+ name = attrs.getQName( i );
+ if (name != null && name.length() == 0) {
+ String prefix;
+ String attrURI;
+
+ name = attrs.getLocalName( i );
+ attrURI = attrs.getURI( i );
+ if (( attrURI != null && attrURI.length() != 0 ) &&
+ ( namespaceURI == null || namespaceURI.length() == 0 ||
+ ! attrURI.equals( namespaceURI ) )) {
+ prefix = getPrefix( attrURI );
+ if (prefix != null && prefix.length() > 0)
+ name = prefix + ":" + name;
+ }
}
- }
-
- value = attrs.getValue( i );
- if ( value == null )
- value = "";
- _printer.printText( name );
- _printer.printText( "=\"" );
- printEscaped( value );
- _printer.printText( '"' );
-
- // If the attribute xml:space exists, determine whether
- // to preserve spaces in this and child nodes based on
- // its value.
- if ( name.equals( "xml:space" ) ) {
- if ( value.equals( "preserve" ) )
- preserveSpace = true;
- else
- preserveSpace = _format.getPreserveSpace();
- }
- }
- }
- if ( _prefixes != null ) {
- Enumeration enum;
-
- enum = _prefixes.keys();
- while ( enum.hasMoreElements() ) {
- _printer.printSpace();
- value = (String) enum.nextElement();
- name = (String) _prefixes.get( value );
- if ( name.length() == 0 ) {
- _printer.printText( "xmlns=\"" );
- printEscaped( value );
- _printer.printText( '"' );
- } else {
- _printer.printText( "xmlns:" );
+ value = attrs.getValue( i );
+ if (value == null)
+ value = "";
_printer.printText( name );
_printer.printText( "=\"" );
printEscaped( value );
_printer.printText( '"' );
+
+ // If the attribute xml:space exists, determine whether
+ // to preserve spaces in this and child nodes based on
+ // its value.
+ if (name.equals( "xml:space" )) {
+ if (value.equals( "preserve" ))
+ preserveSpace = true;
+ else
+ preserveSpace = _format.getPreserveSpace();
+ }
+ }
+ }
+
+ if (_prefixes != null) {
+ Enumeration enum;
+
+ enum = _prefixes.keys();
+ while (enum.hasMoreElements()) {
+ _printer.printSpace();
+ value = (String) enum.nextElement();
+ name = (String) _prefixes.get( value );
+ if (name.length() == 0) {
+ _printer.printText( "xmlns=\"" );
+ printEscaped( value );
+ _printer.printText( '"' );
+ }
+ else {
+ _printer.printText( "xmlns:" );
+ _printer.printText( name );
+ _printer.printText( "=\"" );
+ printEscaped( value );
+ _printer.printText( '"' );
+ }
}
}
- }
- // Now it's time to enter a new element state
- // with the tag name and space preserving.
- // We still do not change the curent element state.
- state = enterElementState( namespaceURI, localName, rawName, preserveSpace );
+ // Now it's time to enter a new element state
+ // with the tag name and space preserving.
+ // We still do not change the curent element state.
+ state = enterElementState( namespaceURI, localName, rawName, preserveSpace );
name = ( localName == null || localName.length() == 0 ) ? rawName : namespaceURI + "^" + localName;
state.doCData = _format.isCDataElement( name );
state.unescaped = _format.isNonEscapingElement( name );
- } catch ( IOException except ) {
+ }
+ catch (IOException except) {
throw new SAXException( except );
}
}
@@ -355,37 +387,42 @@
public void endElement( String namespaceURI, String localName,
String rawName )
- throws SAXException
+ throws SAXException
{
try {
endElementIO( namespaceURI, localName, rawName );
- } catch ( IOException except ) {
+ }
+ catch (IOException except) {
throw new SAXException( except );
}
}
public void endElementIO( String namespaceURI, String localName,
- String rawName )
- throws IOException
+ String rawName )
+ throws IOException
{
ElementState state;
-
+ fNamespaceSupport.popContext();
+ if (DEBUG) {
+ System.out.println("==>endElement: " +rawName);
+ }
// Works much like content() with additions for closing
// an element. Note the different checks for the closed
// element's state and the parent element's state.
_printer.unindent();
state = getElementState();
- if ( state.empty ) {
+ if (state.empty) {
_printer.printText( "/>" );
- } else {
+ }
+ else {
// Must leave CData section first
- if ( state.inCData )
+ if (state.inCData)
_printer.printText( "]]>" );
// This element is not empty and that last content was
// another element, so print a line break before that
// last element and this element's closing tag.
- if ( _indenting && ! state.preserveSpace && (state.afterElement || state.afterComment) )
+ if (_indenting && ! state.preserveSpace && (state.afterElement || state.afterComment))
_printer.breakLine();
_printer.printText( "</" );
_printer.printText( state.rawName );
@@ -397,7 +434,7 @@
state.afterElement = true;
state.afterComment = false;
state.empty = false;
- if ( isDocumentState() )
+ if (isDocumentState())
_printer.flush();
}
@@ -408,7 +445,7 @@
public void startElement( String tagName, AttributeList attrs )
- throws SAXException
+ throws SAXException
{
int i;
boolean preserveSpace;
@@ -417,86 +454,87 @@
String value;
try {
- if ( _printer == null )
- throw new IllegalStateException( "SER002 No writer supplied for serializer" );
+ if (_printer == null)
+ throw new IllegalStateException( "SER002 No writer supplied for serializer" );
- state = getElementState();
- if ( isDocumentState() ) {
- // If this is the root element handle it differently.
- // If the first root element in the document, serialize
- // the document's DOCTYPE. Space preserving defaults
- // to that of the output format.
- if ( ! _started )
- startDocument( tagName );
- } else {
- // For any other element, if first in parent, then
- // close parent's opening tag and use the parnet's
- // space preserving.
- if ( state.empty )
- _printer.printText( '>' );
- // Must leave CData section first
- if ( state.inCData )
- {
- _printer.printText( "]]>" );
- state.inCData = false;
+ state = getElementState();
+ if (isDocumentState()) {
+ // If this is the root element handle it differently.
+ // If the first root element in the document, serialize
+ // the document's DOCTYPE. Space preserving defaults
+ // to that of the output format.
+ if (! _started)
+ startDocument( tagName );
}
- // Indent this element on a new line if the first
- // content of the parent element or immediately
- // following an element.
- if ( _indenting && ! state.preserveSpace &&
- ( state.empty || state.afterElement || state.afterComment) )
- _printer.breakLine();
- }
- preserveSpace = state.preserveSpace;
+ else {
+ // For any other element, if first in parent, then
+ // close parent's opening tag and use the parnet's
+ // space preserving.
+ if (state.empty)
+ _printer.printText( '>' );
+ // Must leave CData section first
+ if (state.inCData) {
+ _printer.printText( "]]>" );
+ state.inCData = false;
+ }
+ // Indent this element on a new line if the first
+ // content of the parent element or immediately
+ // following an element.
+ if (_indenting && ! state.preserveSpace &&
+ ( state.empty || state.afterElement || state.afterComment))
+ _printer.breakLine();
+ }
+ preserveSpace = state.preserveSpace;
- // Do not change the current element state yet.
- // This only happens in endElement().
+ // Do not change the current element state yet.
+ // This only happens in endElement().
- _printer.printText( '<' );
- _printer.printText( tagName );
- _printer.indent();
-
- // For each attribute print it's name and value as one part,
- // separated with a space so the element can be broken on
- // multiple lines.
- if ( attrs != null ) {
- for ( i = 0 ; i < attrs.getLength() ; ++i ) {
- _printer.printSpace();
- name = attrs.getName( i );
- value = attrs.getValue( i );
- if ( value != null ) {
- _printer.printText( name );
- _printer.printText( "=\"" );
- printEscaped( value );
- _printer.printText( '"' );
- }
+ _printer.printText( '<' );
+ _printer.printText( tagName );
+ _printer.indent();
+
+ // For each attribute print it's name and value as one part,
+ // separated with a space so the element can be broken on
+ // multiple lines.
+ if (attrs != null) {
+ for (i = 0 ; i < attrs.getLength() ; ++i) {
+ _printer.printSpace();
+ name = attrs.getName( i );
+ value = attrs.getValue( i );
+ if (value != null) {
+ _printer.printText( name );
+ _printer.printText( "=\"" );
+ printEscaped( value );
+ _printer.printText( '"' );
+ }
- // If the attribute xml:space exists, determine whether
- // to preserve spaces in this and child nodes based on
- // its value.
- if ( name.equals( "xml:space" ) ) {
- if ( value.equals( "preserve" ) )
- preserveSpace = true;
- else
- preserveSpace = _format.getPreserveSpace();
+ // If the attribute xml:space exists, determine whether
+ // to preserve spaces in this and child nodes based on
+ // its value.
+ if (name.equals( "xml:space" )) {
+ if (value.equals( "preserve" ))
+ preserveSpace = true;
+ else
+ preserveSpace = _format.getPreserveSpace();
+ }
}
}
+ // Now it's time to enter a new element state
+ // with the tag name and space preserving.
+ // We still do not change the curent element state.
+ state = enterElementState( null, null, tagName, preserveSpace );
+ state.doCData = _format.isCDataElement( tagName );
+ state.unescaped = _format.isNonEscapingElement( tagName );
}
- // Now it's time to enter a new element state
- // with the tag name and space preserving.
- // We still do not change the curent element state.
- state = enterElementState( null, null, tagName, preserveSpace );
- state.doCData = _format.isCDataElement( tagName );
- state.unescaped = _format.isNonEscapingElement( tagName );
- } catch ( IOException except ) {
+ catch (IOException except) {
throw new SAXException( except );
- }
+ }
}
public void endElement( String tagName )
- throws SAXException
+ throws SAXException
{
endElement( null, null, tagName );
}
@@ -521,55 +559,56 @@
* this is not the first root element of the document.
*/
protected void startDocument( String rootTagName )
- throws IOException
+ throws IOException
{
int i;
String dtd;
dtd = _printer.leaveDTD();
- if ( ! _started ) {
+ if (! _started) {
- if ( ! _format.getOmitXMLDeclaration() ) {
+ if (! _format.getOmitXMLDeclaration()) {
StringBuffer buffer;
// Serialize the document declaration appreaing at the head
// of very XML document (unless asked not to).
buffer = new StringBuffer( "<?xml version=\"" );
- if ( _format.getVersion() != null )
+ if (_format.getVersion() != null)
buffer.append( _format.getVersion() );
else
buffer.append( "1.0" );
buffer.append( '"' );
- if ( _format.getEncoding() != null ) {
+ if (_format.getEncoding() != null) {
buffer.append( " encoding=\"" );
buffer.append( _format.getEncoding() );
buffer.append( '"' );
}
- if ( _format.getStandalone() && _docTypeSystemId == null &&
- _docTypePublicId == null )
+ if (_format.getStandalone() && _docTypeSystemId == null &&
+ _docTypePublicId == null)
buffer.append( " standalone=\"yes\"" );
buffer.append( "?>" );
_printer.printText( buffer );
_printer.breakLine();
}
- if ( ! _format.getOmitDocumentType() ) {
- if ( _docTypeSystemId != null ) {
+ if (! _format.getOmitDocumentType()) {
+ if (_docTypeSystemId != null) {
// System identifier must be specified to print DOCTYPE.
// If public identifier is specified print 'PUBLIC
// <public> <system>', if not, print 'SYSTEM <system>'.
_printer.printText( "<!DOCTYPE " );
_printer.printText( rootTagName );
- if ( _docTypePublicId != null ) {
+ if (_docTypePublicId != null) {
_printer.printText( " PUBLIC " );
printDoctypeURL( _docTypePublicId );
- if ( _indenting ) {
+ if (_indenting) {
_printer.breakLine();
- for ( i = 0 ; i < 18 + rootTagName.length() ; ++i )
+ for (i = 0 ; i < 18 + rootTagName.length() ; ++i)
_printer.printText( " " );
- } else
+ }
+ else
_printer.printText( " " );
- printDoctypeURL( _docTypeSystemId );
+ printDoctypeURL( _docTypeSystemId );
}
else {
_printer.printText( " SYSTEM " );
@@ -578,7 +617,7 @@
// If we accumulated any DTD contents while printing.
// this would be the place to print it.
- if ( dtd != null && dtd.length() > 0 ) {
+ if (dtd != null && dtd.length() > 0) {
_printer.printText( " [" );
printText( dtd, true, true );
_printer.printText( ']' );
@@ -586,7 +625,8 @@
_printer.printText( ">" );
_printer.breakLine();
- } else if ( dtd != null && dtd.length() > 0 ) {
+ }
+ else if (dtd != null && dtd.length() > 0) {
_printer.printText( "<!DOCTYPE " );
_printer.printText( rootTagName );
_printer.printText( " [" );
@@ -608,119 +648,442 @@
* inbetween, but better optimized.
*/
protected void serializeElement( Element elem )
- throws IOException
+ throws IOException
{
Attr attr;
NamedNodeMap attrMap;
int i;
Node child;
ElementState state;
- boolean preserveSpace;
String name;
String value;
String tagName;
+ String prefix;
+ String uri;
+
+
+ fLocalNSCount = 0;
+ fSerializedCount = 0;
+ // add new namespace context
+ fNamespaceSupport.pushContext();
+ if (DEBUG) {
+ System.out.println("==>startElement: " +elem.getNodeName());
+ }
tagName = elem.getTagName();
state = getElementState();
- if ( isDocumentState() ) {
+ if (isDocumentState()) {
// If this is the root element handle it differently.
// If the first root element in the document, serialize
// the document's DOCTYPE. Space preserving defaults
// to that of the output format.
- if ( ! _started )
+
+ // check if document is DOM L1 document
+ fDOML1 = (elem.getLocalName() == null)? true: false;
+
+ if (! _started)
startDocument( tagName );
- } else {
+ }
+ else {
// For any other element, if first in parent, then
- // close parent's opening tag and use the parnet's
+ // close parent's opening tag and use the parent's
// space preserving.
- if ( state.empty )
+ if (state.empty)
_printer.printText( '>' );
// Must leave CData section first
- if ( state.inCData )
- {
+ if (state.inCData) {
_printer.printText( "]]>" );
state.inCData = false;
}
// Indent this element on a new line if the first
// content of the parent element or immediately
// following an element.
- if ( _indenting && ! state.preserveSpace &&
- ( state.empty || state.afterElement || state.afterComment) )
+ if (_indenting && ! state.preserveSpace &&
+ ( state.empty || state.afterElement || state.afterComment))
_printer.breakLine();
}
- preserveSpace = state.preserveSpace;
// Do not change the current element state yet.
// This only happens in endElement().
+ fPreserveSpace = state.preserveSpace;
- _printer.printText( '<' );
- _printer.printText( tagName );
- _printer.indent();
-
- // Lookup the element's attribute, but only print specified
- // attributes. (Unspecified attributes are derived from the DTD.
- // For each attribute print it's name and value as one part,
- // separated with a space so the element can be broken on
- // multiple lines.
+
+ // -----------------------------------------
+ // seach for new namespace binding attributes
+ // -----------------------------------------
+ //
attrMap = elem.getAttributes();
- if ( attrMap != null ) {
- for ( i = 0 ; i < attrMap.getLength() ; ++i ) {
+ int length = 0;
+
+ //-----------------------
+ // get element uri/prefix
+ //-----------------------
+ uri = elem.getNamespaceURI();
+ prefix = elem.getPrefix();
+
+
+ //----------------------
+ // output element name
+ //----------------------
+ if ((uri !=null && prefix !=null ) && uri.length() == 0 && prefix.length()!=0) {
+ // uri is an empty string and element has some prefix
+ // the namespace alg later will fix up the namespace attributes
+ // remove element prefix
+ _printer.printText( '<' );
+ _printer.printText( elem.getLocalName() );
+ _printer.indent();
+ }
+ else {
+ _printer.printText( '<' );
+ _printer.printText( tagName );
+ _printer.indent();
+ }
+
+ // REVISIT: should we report error/warning if DOM 1 nodes mix with DOM 2 nodes?
+
+ // -----------------------------------------
+ // Fix up namespaces for element: per DOM L3
+ // check if prefix/namespace is correct for current element
+ // -----------------------------------------
+ if (uri != null) { // Element has a namespace
+
+ uri = fSymbolTable.addSymbol(uri);
+ prefix = prefix == null ? fEmptySymbol :fSymbolTable.addSymbol(prefix);
+ if (fNamespaceSupport.getURI(prefix) == uri) {
+ // this namespace was declared at parent level
+ // do nothing
+
+ }
+ else {
+ // the prefix is either undeclared
+ // or
+ // conflict: the prefix is bound to another URI
+
+ // check if uri is an empty string && element has prefix
+ if (uri == fEmptySymbol && prefix != fEmptySymbol) {
+
+ // the element prefix is already removed above
+ prefix = fEmptySymbol;
+ if (fNamespaceSupport.getURI(prefix) !=null) {
+ // xmlns default namespace is bound to something
+ // undeclare it
+
+ // print default namespace declaration
+ printNamespaceAttr(prefix, uri);
+ fNamespaceSupport.declarePrefix(prefix, uri);
+ }
+ }
+ else {
+ // add or modify local declaration
+ printNamespaceAttr(prefix, uri);
+ fNamespaceSupport.declarePrefix(prefix, uri);
+ }
+
+ }
+ }
+ else { // Element has no namespace
+
+ int colon = tagName.indexOf(':');
+ if (colon > -1) {
+ // DOM Level 1 node!
+ int colon2 = tagName.lastIndexOf(':');
+ if (colon != colon2) {
+ //not a QName: report an error
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Element's name is not a QName: "+tagName, DOMError.SEVERITY_ERROR);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ // REVISIT: should we terminate upon request?
+ }
+ }
+ else {
+ // if we got here no namespace processing was performed
+ // report warnings
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Element <"+tagName+"> does not belong to any namespace: prefix could be undeclared or bound to some namespace", DOMError.SEVERITY_WARNING);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ }
+ }
+ }
+ else { // uri=null and no colon
+
+ if (fNamespaceSupport.getURI(fEmptySymbol) !=null) {
+ // there is a default namespace decl that is bound to something else
+ printNamespaceAttr(fEmptySymbol, fEmptySymbol);
+ fNamespaceSupport.declarePrefix(fEmptySymbol, uri);
+
+ }
+ }
+ }
+
+ // -----------------------------------------
+ // Fix up namespaces for attributes: per DOM L3
+ // check if prefix/namespace is correct the attributes
+ // -----------------------------------------
+
+ if (attrMap !=null) {
+
+ for (i = 0; i < attrMap.getLength(); i++) {
+
attr = (Attr) attrMap.item( i );
- name = attr.getName();
value = attr.getValue();
- if ( value == null )
- value = "";
- if ( attr.getSpecified() || !getFeature("discard-default-content") ) {
- _printer.printSpace();
- _printer.printText( name );
- _printer.printText( "=\"" );
- printEscaped( value );
- _printer.printText( '"' );
+ name = attr.getNodeName();
+ if (DEBUG) {
+ System.out.println("==>process attribute: "+attr.getNodeName());
}
- // If the attribute xml:space exists, determine whether
- // to preserve spaces in this and child nodes based on
- // its value.
- if ( name.equals( "xml:space" ) ) {
- if ( value.equals( "preserve" ) )
- preserveSpace = true;
- else
- preserveSpace = _format.getPreserveSpace();
+ uri = attr.getNamespaceURI();
+
+
+
+ if (uri != null) { // attribute has namespace !=null
+ prefix = attr.getPrefix();
+ prefix = prefix == null ? fEmptySymbol :fSymbolTable.addSymbol(prefix);
+ String localpart = fSymbolTable.addSymbol( attr.getLocalName());
+
+ uri = fSymbolTable.addSymbol(uri);
+
+ // find if for this prefix a URI was already declared
+ String declaredURI = fNamespaceSupport.getURI(prefix);
+
+ // check if attribute is a namespace decl
+ if (prefix == fXmlnsSymbol) { //xmlns:prefix
+
+ // REVISIT: should we skip invalid xmlns declaration
+ // xmlns:foo = "" ??
+ if (fNamespaceSupport.getURI(localpart) == null) {
+ // this declaration is not in the scope
+ printNamespaceAttr(localpart, value);
+ fNamespaceSupport.declarePrefix(localpart, value);
+ }
+ continue;
+ }
+ else if (localpart == fXmlnsSymbol && prefix == fEmptySymbol) { // xmlns
+ if (fNamespaceSupport.getURI(fEmptySymbol) == null) {
+ // this declaration is not in the scope
+ printNamespaceAttr(fEmptySymbol, value);
+ fNamespaceSupport.declarePrefix(fEmptySymbol, value);
+ }
+ continue;
+
+ }
+
+ if (prefix == fEmptySymbol || declaredURI != uri) {
+ // attribute has no prefix (default namespace decl does not apply to attributes)
+ // OR
+ // attribute prefix is not declared
+ // OR
+ // conflict: attr URI does not match the prefix in scope
+
+ name = attr.getNodeName();
+ // Find if any prefix for attributes namespace URI is available
+ // in the scope
+ String declaredPrefix = fNamespaceSupport.getPrefix(uri);
+ if (declaredPrefix == null || declaredPrefix == fEmptySymbol) {
+ // could not find a prefix/prefix is empty string
+ if (DEBUG) {
+ System.out.println("==> cound not find prefix for the attribute: " +prefix);
+ }
+ if (prefix != fEmptySymbol) {
+ // no need to create a new prefix:
+ // use the one on the attribute
+ } else {
+ // create new prefix
+ prefix = "NS" +fNamespaceCounter++;
+ }
+ // add declaration for the new prefix
+ printNamespaceAttr(prefix, uri);
+ fNamespaceSupport.declarePrefix(prefix, uri);
+ } else {
+ // use the prefix that was found (declared previously for this URI
+ prefix = declaredPrefix;
+ }
+ name=prefix+":"+localpart;
+ // change prefix for this attribute
+ }
+
+ printAttribute (name, (value==null)?fEmptySymbol:value, attr.getSpecified());
+ }
+ else { // attribute uri == null
+
+ // data
+ name = attr.getNodeName();
+ int colon = name.indexOf(':');
+ int colon2 = name.lastIndexOf(':');
+ value = attr.getValue();
+ // check if attribute is a namespace decl
+ if (name.startsWith(fXmlnsSymbol)) {
+ //
+ // DOM Level 1 node!
+ //
+ if (colon < 0) { // xmlns decl
+ if (fNamespaceSupport.getURI(fEmptySymbol) == null) {
+ // this declaration is not in the scope
+ fNamespaceSupport.declarePrefix(fEmptySymbol, (value==null)?fEmptySymbol:value);
+ }
+ else {
+ // duplicate declaration
+ // skip
+ continue;
+ }
+
+ }
+ else if (colon == colon2) { // xmlns:prefix decl
+ // get prefix
+ prefix = name.substring(6);
+ if (prefix.length() == 0) {
+ // report an error - invalid namespace declaration
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Namespace declaration syntax is incorrect "+name, DOMError.SEVERITY_ERROR);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ }
+ // REVISIT: skip invalid declaration?
+ // continue;
+
+ }
+ else if (value != null && value.length() == 0) {
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Namespace declaration syntax is incorrect "+name, DOMError.SEVERITY_ERROR);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ }
+ // REVISIT: skip invalid declaration?
+ // continue;
+ }
+ else if (fNamespaceSupport.getURI(prefix) == null) {
+ // this declaration is not in the scope
+ fNamespaceSupport.declarePrefix(prefix, value);
+
+ }
+ } else { // colon !=colon
+ // will report error for this case later in the code
+ }
+
+ }
+
+ if (colon > -1) {
+ //
+ // DOM Level 1 node!
+ //
+ if (colon != colon2) {
+ //not a QName: report an error
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Attribute's name is not a QName: "+name, DOMError.SEVERITY_ERROR);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ }
+
+ }
+ else {
+ // if we got here no namespace processing was performed
+ // report warnings
+ if (fDOMErrorHandler != null) {
+ modifyDOMError("Attribute '"+name+"' does not belong to any namespace: prefix could be undeclared or bound to some namespace", DOMError.SEVERITY_WARNING);
+ boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
+ }
+ }
+
+ // REVISIT: should we skip invalid declarations?
+ printAttribute (name, (value==null)?fEmptySymbol:value, attr.getSpecified());
+ }
+ else { // uri=null and no colon
+ // no fix up is needed: default namespace decl does not
+ // apply to attributes
+
+ printAttribute (name, (value==null)?fEmptySymbol:value, attr.getSpecified());
+ }
+
}
}
}
+
+
// If element has children, then serialize them, otherwise
- // serialize en empty tag.
- if ( elem.hasChildNodes() ) {
+ // serialize en empty tag.
+ if (elem.hasChildNodes()) {
// Enter an element state, and serialize the children
// one by one. Finally, end the element.
- state = enterElementState( null, null, tagName, preserveSpace );
+ state = enterElementState( null, null, tagName, fPreserveSpace );
state.doCData = _format.isCDataElement( tagName );
state.unescaped = _format.isNonEscapingElement( tagName );
child = elem.getFirstChild();
- while ( child != null ) {
+ while (child != null) {
serializeNode( child );
child = child.getNextSibling();
}
endElementIO( null, null, tagName );
- } else {
+ }
+ else {
+ if (DEBUG) {
+ System.out.println("==>endElement: " +elem.getNodeName());
+ }
+ fNamespaceSupport.popContext();
_printer.unindent();
_printer.printText( "/>" );
// After element but parent element is no longer empty.
state.afterElement = true;
state.afterComment = false;
state.empty = false;
- if ( isDocumentState() )
+ if (isDocumentState())
_printer.flush();
}
}
- protected String getEntityRef( int ch )
- {
+
+ /**
+ * Serializes a namespace attribute with the given prefix and value for URI.
+ * In case prefix is empty will serialize default namespace declaration.
+ *
+ * @param prefix
+ * @param uri
+ * @exception IOException
+ */
+
+ private void printNamespaceAttr(String prefix, String uri) throws IOException{
+ _printer.printSpace();
+ if (prefix == fEmptySymbol) {
+ _printer.printText( fXmlnsSymbol );
+ }
+ else {
+ _printer.printText( fXmlnsSymbol+ ":"+prefix );
+ }
+ _printer.printText( "=\"" );
+ printEscaped( uri );
+ _printer.printText( '"' );
+ }
+
+ /**
+ * Prints attribute.
+ * NOTE: xml:space attribute modifies output format
+ *
+ * @param name
+ * @param value
+ * @param isSpecified
+ * @exception IOException
+ */
+ private void printAttribute (String name, String value, boolean isSpecified) throws IOException{
+
+ if (isSpecified || !getFeature("discard-default-content")) {
+ _printer.printSpace();
+ _printer.printText( name );
+ _printer.printText( "=\"" );
+ printEscaped( value );
+ _printer.printText( '"' );
+ }
+
+ // If the attribute xml:space exists, determine whether
+ // to preserve spaces in this and child nodes based on
+ // its value.
+ if (name.equals( "xml:space" )) {
+ if (value.equals( "preserve" ))
+ fPreserveSpace = true;
+ else
+ fPreserveSpace = _format.getPreserveSpace();
+ }
+ }
+
+ protected String getEntityRef( int ch ) {
// Encode special XML characters into the equivalent character references.
// These five are defined by default for all XML documents.
- switch ( ch ) {
+ switch (ch) {
case '<':
return "lt";
case '>':
@@ -740,7 +1103,7 @@
*
*/
private Attributes extractNamespaces( Attributes attrs )
- throws SAXException
+ throws SAXException
{
AttributesImpl attrsOnly;
String rawName;
@@ -752,17 +1115,18 @@
length = attrs.getLength();
attrsOnly = new AttributesImpl( attrs );
- for ( i = length - 1 ; i >= 0 ; --i ) {
+ for (i = length - 1 ; i >= 0 ; --i) {
rawName = attrsOnly.getQName( i );
//We have to exclude the namespaces declarations from the attributes
//Append only when the feature http://xml.org/sax/features/namespace-prefixes"
//is TRUE
- if ( rawName.startsWith( "xmlns" ) ) {
+ if (rawName.startsWith( "xmlns" )) {
if (rawName.length() == 5) {
startPrefixMapping( "", attrs.getValue( i ) );
attrsOnly.removeAttribute( i );
- } else if (rawName.charAt(5) == ':') {
+ }
+ else if (rawName.charAt(5) == ':') {
startPrefixMapping(rawName.substring(6), attrs.getValue(i));
attrsOnly.removeAttribute( i );
}
@@ -770,9 +1134,10 @@
}
return attrsOnly;
}
-
+
+
// *****************************
-
+
private void initFeatures() {
fFeatures.put("normalize-characters",new Boolean(false));
fFeatures.put("split-cdata-sections",new Boolean(true));
@@ -783,7 +1148,7 @@
fFeatures.put("format-canonical",new Boolean(false));
fFeatures.put("format-pretty-print",new Boolean(false));
}
-
+
private void checkAllFeatures() {
if (getFeature("whitespace-in-element-content"))
_format.setPreserveSpace(true);
@@ -807,7 +1172,7 @@
*/
public void setFeature(String name,
boolean state)
- throws DOMException {
+ throws DOMException {
if (name != null && fFeatures.containsKey(name))
if (canSetFeature(name,state))
fFeatures.put(name,new Boolean(state));
@@ -830,19 +1195,19 @@
*/
public boolean canSetFeature(String name, boolean state) {
if (name.equals("normalize-characters") && state)
- return false;
+ return false;
else if (name.equals("validation") && state)
- return false;
+ return false;
else if (name.equals("whitespace-in-element-content") && !state)
- return false;
+ return false;
else if (name.equals("format-canonical") && state)
- return false;
+ return false;
else if (name.equals("format-pretty-print") && state)
- return false;
+ return false;
else
- return true;
+ return true;
}
-
+
/**
* Look up the value of a feature.
* <br>The feature name has the same form as a DOM hasFeature string
@@ -855,7 +1220,7 @@
* recognize the feature name.
*/
public boolean getFeature(String name)
- throws DOMException {
+ throws DOMException {
Boolean state = (Boolean)fFeatures.get(name);
if (state == null)
throw new DOMException(DOMException.NOT_FOUND_ERR,"Feature "+name+" not found");
@@ -875,7 +1240,7 @@
public String getEncoding() {
return fEncoding;
}
-
+
/**
* The character encoding in which the output will be written.
* <br> The encoding to use when writing is determined as follows: If the
@@ -925,7 +1290,7 @@
public String getNewLine() {
return _format.getLineSeparator();
}
-
+
/**
* The end-of-line sequence of characters to be used in the XML being
* written out. The only permitted values are these:
@@ -962,7 +1327,7 @@
public DOMErrorHandler getErrorHandler() {
return fDOMErrorHandler;
}
-
+
/**
* The error handler that will receive error notifications during
* serialization. The node where the error occured is passed to this
@@ -995,7 +1360,7 @@
*/
public boolean writeNode(java.io.OutputStream destination,
Node wnode)
- throws Exception {
+ throws Exception {
checkAllFeatures();
try {
setOutputByteStream(destination);
@@ -1010,10 +1375,10 @@
else
return false;
}
- catch(NullPointerException npe) {
+ catch (NullPointerException npe) {
throw npe;
}
- catch(IOException ioe) {
+ catch (IOException ioe) {
throw ioe;
}
fLastEncoding = getEncoding();
@@ -1037,7 +1402,7 @@
* <code>DOMString</code>.
*/
public String writeToString(Node wnode)
- throws DOMException {
+ throws DOMException {
checkAllFeatures();
StringWriter destination = new StringWriter();
try {
@@ -1053,13 +1418,27 @@
else
return null;
}
- catch(IOException ioe) {
+ catch (IOException ioe) {
throw new DOMException(DOMException.DOMSTRING_SIZE_ERR,"The resulting string is too long to fit in a DOMString: "+ioe.getMessage());
}
fLastEncoding = getEncoding();
return destination.toString();
}
+ public boolean reset() {
+ super.reset();
+ fNamespaceSupport.reset(fSymbolTable);
+ fNamespaceCounter = 1;
+ fLocalNSCount = 0;
+ fSerializedCount = 0;
+ fXmlSymbol = fSymbolTable.addSymbol("xml");
+ fXmlnsSymbol = fSymbolTable.addSymbol("xmlns");
+ fEmptySymbol=fSymbolTable.addSymbol("");
+ return true;
+
+ }
+
}
+
---------------------------------------------------------------------
To unsubscribe, e-mail: xerces-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xerces-cvs-help@xml.apache.org