// XMLWriter.java - serialize an XML document.
// Written by David Megginson, [email protected]
// NO WARRANTY! This class is in the public domain.
package nu.xom.tests;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Hashtable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.NamespaceSupport;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* <p>
* The original version of this class was written and placed in the
* public domain by David Megginson. Elliotte Rusty Harold added
* <code>LexicalHandler</code> support. It is included here purely
* for help with testing the <code>SAXConverter</code> class. It is
* not part of the XOM API; nor is it used internally by XOM anywhere
* except in the <code>SAXConverter</code> tests.
* </p>
*
* <p>
* This class does not properly preserve additional namespace
* declarations in non-root elements. If you encounter that, the
* bug is here, not in <code>SAXConverter</code>.
* </p>
*
* @author David Megginson, Elliotte Rusty Harold
* @version 1.0
*/
class XMLWriter extends XMLFilterImpl implements LexicalHandler {
///////////////////////////////////////////////////////////////////
// Constructors.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Create a new XML writer.
* </p>
*
* <p>Write to standard output.</p>
*/
public XMLWriter() {
init(null);
}
/**
* <p>
* Create a new XML writer.
* </p>
*
* <p>Write to the writer provided.</p>
*
* @param writer the output destination, or null to use standard
* output
*/
public XMLWriter (Writer writer) {
init(writer);
}
/**
* <p>
* Internal initialization method.
* </p>
*
* <p>All of the public constructors invoke this method.
*
* @param writer the output destination, or null to use
* standard output.
*/
private void init (Writer writer) {
setOutput(writer);
nsSupport = new NamespaceSupport();
prefixTable = new Hashtable();
forcedDeclTable = new Hashtable();
doneDeclTable = new Hashtable();
}
///////////////////////////////////////////////////////////////////
// Public methods.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Reset the writer.
* </p>
*
* <p>This method is especially useful if the writer throws an
* exception before it is finished, and you want to reuse the
* writer for a new document. It is usually a good idea to
* invoke {@link #flush flush} before resetting the writer,
* to make sure that no output is lost.</p>
*
* <p>This method is invoked automatically by the
* {@link #startDocument startDocument} method before writing
* a new document.</p>
*
* <p><strong>Note:</strong> this method will <em>not</em>
* clear the prefix or URI information in the writer or
* the selected output writer.</p>
*
* @see #flush
*/
public void reset() {
elementLevel = 0;
prefixCounter = 0;
nsSupport.reset();
}
/**
* <p>
* Flush the output.
* </p>
*
* <p>This method flushes the output stream. It is especially useful
* when you need to make certain that the entire document has
* been written to output but do not want to close the output
* stream.</p>
*
* <p>This method is invoked automatically by the
* {@link #endDocument endDocument} method after writing a
* document.</p>
*
* @throws IOException
*
* @see #reset
*
*/
public void flush() throws IOException {
output.flush();
}
/**
* <p>
* Set a new output destination for the document.
* </p>
*
* @param writer the output destination, or null to use
* standard output
*
* @return the current output writer
*
* @see #flush
*/
public void setOutput (Writer writer) {
if (writer == null) {
output = new OutputStreamWriter(System.out);
}
else {
output = writer;
}
}
/**
* <p>
* Specify a preferred prefix for a namespace URI.
* </p>
*
* <p>Note that this method does not actually force the namespace
* to be declared; to do that, use the {@link
* #forceNSDecl(java.lang.String) forceNSDecl} method as well.</p>
*
* @param uri the namespace URI
* @param prefix the preferred prefix, or "" to select
* the default namespace
*
* @see #getPrefix
* @see #forceNSDecl(java.lang.String)
* @see #forceNSDecl(java.lang.String,java.lang.String)
*/
public void setPrefix (String uri, String prefix) {
prefixTable.put(uri, prefix);
}
/**
* <p>
* Get the current or preferred prefix for a namespace URI.
* </p>
*
* @param uri the namespace URI
*
* @return the preferred prefix, or "" for the default namespace
*
* @see #setPrefix
*/
public String getPrefix (String uri) {
return (String)prefixTable.get(uri);
}
public void startPrefixMapping(String prefix, String uri) {
this.forceNSDecl(uri, prefix);
}
/**
* <p>
* Force a namespace to be declared on the root element.
* </p>
*
* <p>By default, the XMLWriter will declare only the namespaces
* needed for an element; as a result, a namespace may be
* declared many places in a document if it is not used on the
* root element.</p>
*
* <p>This method forces a namespace to be declared on the root
* element even if it is not used there, and reduces the number
* of xmlns attributes in the document.</p>
*
* @param uri the namespace URI to declare
*
* @see #forceNSDecl(java.lang.String,java.lang.String)
* @see #setPrefix
*/
public void forceNSDecl (String uri) {
forcedDeclTable.put(uri, Boolean.TRUE);
}
/**
* <p>
* Force a namespace declaration with a preferred prefix.
* </p>
*
* <p>This is a convenience method that invokes {@link
* #setPrefix setPrefix} then {@link #forceNSDecl(java.lang.String)
* forceNSDecl}.</p>
*
* @param uri the namespace URI to declare on the root element
* @param prefix the preferred prefix for the namespace, or ""
* for the default namespace
*
* @see #setPrefix
* @see #forceNSDecl(java.lang.String)
*/
public void forceNSDecl (String uri, String prefix) {
setPrefix(uri, prefix);
forceNSDecl(uri);
}
///////////////////////////////////////////////////////////////////
// Methods from org.xml.sax.ContentHandler.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Write the XML declaration at the beginning of the document.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @throws org.xml.sax.SAXException if there is an error
* writing the XML declaration, or if a handler further
* down the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#startDocument
*/
public void startDocument() throws SAXException {
reset();
write("<?xml version=\"1.0\" standalone=\"yes\"?>\n\n");
super.startDocument();
}
/**
* <p>
* Write a newline at the end of the document.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @throws org.xml.sax.SAXException if there is an error
* writing the newline, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#endDocument
*/
public void endDocument() throws SAXException {
write('\n');
super.endDocument();
try {
flush();
} catch (IOException ex) {
throw new SAXException(ex);
}
}
/**
* <p>
* Write a start-tag.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @param uri the namespace URI, or the empty string if none
* is available
* @param localName the element's local (unprefixed) name (required)
* @param qualifiedName the element's qualified (prefixed) name,
* or the empty string is none is available. This method
* will use the qualified name as a template for generating
* a prefix if necessary, but it is not guaranteed to use
* the same qualified name.
* @param atts the element's attribute list (must not be null)
*
* @throws org.xml.sax.SAXException if there is an error
* writing the start-tag, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#startElement
*/
public void startElement (String uri, String localName,
String qualifiedName, Attributes atts) throws SAXException {
elementLevel++;
nsSupport.pushContext();
write('<');
writeName(uri, localName, qualifiedName, true);
writeAttributes(atts);
if (elementLevel == 1) {
forceNSDecls();
}
writeNSDecls();
write('>');
super.startElement(uri, localName, qualifiedName, atts);
}
/**
* <p>
* Write an end-tag.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @param uri the namespace URI, or the empty string if none
* is available
* @param localName the element's local (unprefixed) name (required)
* @param qualifiedName the element's qualified (prefixed) name, or the
* empty string is none is available. This method will
* use the qName as a template for generating a prefix
* if necessary, but it is not guaranteed to use the
* same qualified name.
*
* @throws org.xml.sax.SAXException if there is an error
* writing the end-tag, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#endElement
*/
public void endElement (String uri, String localName, String qualifiedName)
throws SAXException {
write("</");
writeName(uri, localName, qualifiedName, true);
write('>');
if (elementLevel == 1) {
write('\n');
}
super.endElement(uri, localName, qualifiedName);
nsSupport.popContext();
elementLevel--;
}
/**
* <p>
* Write character data.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @param ch the array of characters to write
* @param start the starting position in the array
* @param length the number of characters to write
*
* @throws org.xml.sax.SAXException if there is an error
* writing the characters, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#characters
*/
public void characters (char[] ch, int start, int length)
throws SAXException {
writeEsc(ch, start, length, false);
super.characters(ch, start, length);
}
/**
* <p>
* Write ignorable whitespace.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @param ch the array of characters to write
* @param start the starting position in the array
* @param length the number of characters to write
*
* @throws org.xml.sax.SAXException if there is an error
* writing the whitespace, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#ignorableWhitespace
*/
public void ignorableWhitespace (char[] ch, int start, int length)
throws SAXException {
writeEsc(ch, start, length, false);
super.ignorableWhitespace(ch, start, length);
}
/**
* <p>
* Write a processing instruction.
* </p>
*
* <p>
* Pass the event on down the filter chain for further processing.
* </p>
*
* @param target the processing instruction target
* @param data the processing instruction data
*
* @throws org.xml.sax.SAXException if there is an error
* writing the PI, or if a handler further down
* the filter chain raises an exception
*
* @see org.xml.sax.ContentHandler#processingInstruction
*/
public void processingInstruction (String target, String data)
throws SAXException {
write("<?");
write(target);
write(' ');
write(data);
write("?>");
if (elementLevel < 1) {
write('\n');
}
super.processingInstruction(target, data);
}
///////////////////////////////////////////////////////////////////
// Additional markup.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Write an empty element.
* </p>
*
* <p>
* This method writes an empty-element tag rather than a start-tag
* followed by an end-tag. Both a {@link #startElement
* startElement} and an {@link #endElement endElement} event will
* be passed on down the filter chain.
* </p>
*
* @param uri the element's namespace URI, or the empty string
* if the element has no namespace or if namespace
* processing is not being performed
* @param localName the element's local name (without prefix). This
* parameter must be provided.
* @param qualifiedName the element's qualified name (with prefix), or
* the empty string if none is available. This parameter
* is strictly advisory: the writer may or may not use
* the prefix attached.
* @param atts the element's attribute list
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement
* @see #endElement
*/
public void emptyElement (String uri, String localName,
String qualifiedName, Attributes atts) throws SAXException {
nsSupport.pushContext();
write('<');
writeName(uri, localName, qualifiedName, true);
writeAttributes(atts);
if (elementLevel == 1) {
forceNSDecls();
}
writeNSDecls();
write("/>");
super.startElement(uri, localName, qualifiedName, atts);
super.endElement(uri, localName, qualifiedName);
}
///////////////////////////////////////////////////////////////////
// Convenience methods.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Start a new element without a qualified name or attributes.
* </p>
*
* <p>This method will provide a default empty attribute
* list and an empty string for the qualified name.
* It invokes {@link
* #startElement(String, String, String, Attributes)}
* directly.</p>
*
* @param uri the element's namespace URI
* @param localName the element's local name
*
* @throws org.xml.sax.SAXException if there is an error
* writing the start-tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement(String, String, String, Attributes)
*/
public void startElement (String uri, String localName)
throws SAXException {
startElement(uri, localName, "", EMPTY_ATTS);
}
/**
* <p>
* Start a new element without a qualified name,
* attributes or a namespace URI.</p>
*
* <p>This method will provide an empty string for the
* namespace URI, and empty string for the qualified name,
* and a default empty attribute list. It invokes
* #startElement(String, String, String, Attributes)}
* directly.</p>
*
* @param localName the element's local name
*
* @throws org.xml.sax.SAXException if there is an error
* writing the start-tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement(String, String, String, Attributes)
*/
public void startElement (String localName) throws SAXException {
startElement("", localName, "", EMPTY_ATTS);
}
/**
* <p>
* End an element without a qualfied name.
* </p>
*
* <p>This method will supply an empty string for the qName.
* It invokes {@link #endElement(String, String, String)}
* directly.</p>
*
* @param uri the element's namespace URI
* @param localName the element's local name
*
* @throws org.xml.sax.SAXException if there is an error
* writing the end-tag, or if a handler further down
* the filter chain raises an exception
*
* @see #endElement(String, String, String)
*/
public void endElement(String uri, String localName)
throws SAXException {
endElement(uri, localName, "");
}
/**
* <p>
* End an element without a namespace URI or qualfiied name.
* </p>
*
* <p>This method will supply an empty string for the qName
* and an empty string for the namespace URI.
* It invokes {@link #endElement(String, String, String)}
* directly.</p>
*
* @param localName the element's local name`
*
* @throws org.xml.sax.SAXException if there is an error
* writing the end-tag, or if a handler further down
* the filter chain raises an exception
*
* @see #endElement(String, String, String)
*/
public void endElement(String localName) throws SAXException {
endElement("", localName, "");
}
/**
* <p>
* Add an empty element without a qualified name or attributes.
* </p>
*
* <p>This method will supply an empty string for the qualified name
* and an empty attribute list. It invokes
* {@link #emptyElement(String, String, String, Attributes)}
* directly.</p>
*
* @param uri the element's namespace URI
* @param localName the element's local name
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #emptyElement(String, String, String, Attributes)
*/
public void emptyElement (String uri, String localName)
throws SAXException {
emptyElement(uri, localName, "", EMPTY_ATTS);
}
/**
* <p>
* Add an empty element without a namespace URI, qualified
* name or attributes.
* </p>
*
* <p>This method will supply an empty string for the qualified
* name, and empty string for the namespace URI, and an empty
* attribute list. It invokes
* {@link #emptyElement(String, String, String, Attributes)}
* directly.</p>
*
* @param localName the element's local name
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #emptyElement(String, String, String, Attributes)
*/
public void emptyElement (String localName) throws SAXException {
emptyElement("", localName, "", EMPTY_ATTS);
}
/**
* <p>
* Write an element with character data content.
* </p>
*
* <p>This is a convenience method to write a complete element
* with character data content, including the start-tag
* and end-tag.</p>
*
* <p>This method invokes
* {@link #startElement(String, String, String, Attributes)},
* followed by
* {@link #characters(String)}, followed by
* {@link #endElement(String, String, String)}.</p>
*
* @param uri the element's namespace URI
* @param localName the element's local name
* @param qualifiedName the element's default qualified name
* @param atts the element's attributes
* @param content the character data content
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement(String, String, String, Attributes)
* @see #characters(String)
* @see #endElement(String, String, String)
*/
public void dataElement (String uri, String localName,
String qualifiedName, Attributes atts, String content)
throws SAXException {
startElement(uri, localName, qualifiedName, atts);
characters(content);
endElement(uri, localName, qualifiedName);
}
/**
* <p>
* Write an element with character data content but no attributes.
* </p>
*
* <p>This is a convenience method to write a complete element
* with character data content, including the start-tag
* and end-tag. This method provides an empty string
* for the qualified name and an empty attribute list.</p>
*
* <p>This method invokes
* {@link #startElement(String, String, String, Attributes)},
* followed by
* {@link #characters(String)}, followed by
* {@link #endElement(String, String, String)}.</p>
*
* @param uri the element's namespace URI
* @param localName the element's local name
* @param content the character data content
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement(String, String, String, Attributes)
* @see #characters(String)
* @see #endElement(String, String, String)
*/
public void dataElement(String uri, String localName, String content)
throws SAXException {
dataElement(uri, localName, "", EMPTY_ATTS, content);
}
/**
* <p>
* Write an element with character data content but no attributes
* or namespace URI.
* </p>
*
* <p>This is a convenience method to write a complete element
* with character data content, including the start-tag
* and end-tag. The method provides an empty string for the
* namespace URI, and empty string for the qualified name,
* and an empty attribute list.</p>
*
* <p>This method invokes
* {@link #startElement(String, String, String, Attributes)},
* followed by
* {@link #characters(String)}, followed by
* {@link #endElement(String, String, String)}.</p>
*
* @param localName the element's local name
* @param content the character data content
*
* @throws org.xml.sax.SAXException if there is an error
* writing the empty tag, or if a handler further down
* the filter chain raises an exception
*
* @see #startElement(String, String, String, Attributes)
* @see #characters(String)
* @see #endElement(String, String, String)
*/
public void dataElement (String localName, String content)
throws SAXException {
dataElement("", localName, "", EMPTY_ATTS, content);
}
/**
* <p>
* Write a string of character data, with XML escaping.
* </p>
*
* <p>This is a convenience method that takes an XML
* String, converts it to a character array, then invokes
* {@link #characters(char[], int, int)}.</p>
*
* @param data the character data
* @throws org.xml.sax.SAXException if there is an error
* writing the string, or if a handler further down
* the filter chain raises an exception
* @see #characters(char[], int, int)
*/
public void characters(String data) throws SAXException {
char[] ch = data.toCharArray();
characters(ch, 0, ch.length);
}
///////////////////////////////////////////////////////////////////
// Internal methods.
///////////////////////////////////////////////////////////////////
/**
* <p>
* Force all namespaces to be declared.
* </p>
*
* <p>
* This method is used on the root element to ensure that
* the predeclared namespaces all appear.
* </p>
*/
private void forceNSDecls() {
Enumeration prefixes = forcedDeclTable.keys();
while (prefixes.hasMoreElements()) {
String prefix = (String)prefixes.nextElement();
doPrefix(prefix, null, true);
}
}
/**
* <p>
* Determine the prefix for an element or attribute name.
* </p>
*
* TODO: this method probably needs some cleanup.
*
* @param uri the namespace URI
* @param qName the qualified name (optional); this will be used
* to indicate the preferred prefix if none is currently
* bound.
* @param isElement true if this is an element name, false
* if it is an attribute name (which cannot use the
* default namespace).
*/
private String doPrefix (String uri, String qName, boolean isElement) {
String defaultNS = nsSupport.getURI("");
if ("".equals(uri)) {
if (isElement && defaultNS != null)
nsSupport.declarePrefix("", "");
return null;
}
String prefix;
if (isElement && defaultNS != null && uri.equals(defaultNS)) {
prefix = "";
} else {
prefix = nsSupport.getPrefix(uri);
}
if (prefix != null) {
return prefix;
}
prefix = (String) doneDeclTable.get(uri);
if (prefix != null &&
((!isElement || defaultNS != null) &&
"".equals(prefix) || nsSupport.getURI(prefix) != null)) {
prefix = null;
}
if (prefix == null) {
prefix = (String) prefixTable.get(uri);
if (prefix != null &&
((!isElement || defaultNS != null) &&
"".equals(prefix) || nsSupport.getURI(prefix) != null)) {
prefix = null;
}
}
if (prefix == null && qName != null && !"".equals(qName)) {
int i = qName.indexOf(':');
if (i == -1) {
if (isElement && defaultNS == null) {
prefix = "";
}
} else {
prefix = qName.substring(0, i);
}
}
for (;
prefix == null || nsSupport.getURI(prefix) != null;
prefix = "__NS" + ++prefixCounter)
;
nsSupport.declarePrefix(prefix, uri);
doneDeclTable.put(uri, prefix);
return prefix;
}
/**
* <p>
* Write a raw character.
* </p>
*
* @param c the character to write
*
* @throws org.xml.sax.SAXException if there is an error writing
* the character, this method will throw an IOException
* wrapped in a SAXException
*/
private void write(char c) throws SAXException {
try {
output.write(c);
}
catch (IOException ex) {
throw new SAXException(ex);
}
}
/**
* <p>
* Write a raw string.
* </p>
*
* @param s
*
* @throws org.xml.sax.SAXException if there is an error writing
* the string, this method will throw an IOException
* wrapped in a SAXException
*/
private void write (String s) throws SAXException {
try {
output.write(s);
}
catch (IOException e) {
throw new SAXException(e);
}
}
/**
* <p>
* Write out an attribute list, escaping values.
*</p>
*
* <p>
* The names will have prefixes added to them.
* </p>
*
* @param atts the attribute list to write
*
* @throws org.xml.SAXException if there is an error writing
* the attribute list, this method will throw an
* IOException wrapped in a SAXException
*/
private void writeAttributes (Attributes atts)
throws SAXException {
int len = atts.getLength();
for (int i = 0; i < len; i++) {
char[] ch = atts.getValue(i).toCharArray();
write(' ');
writeName(atts.getURI(i), atts.getLocalName(i),
atts.getQName(i), false);
write("=\"");
writeEsc(ch, 0, ch.length, true);
write('"');
}
}
/**
* <p>
* Write an array of data characters with escaping.
* </p>
*
* @param ch the array of characters
* @param start the starting position
* @param length the number of characters to use
* @param isAttVal true if this is an attribute value literal
*
* @throws org.xml.SAXException if there is an error writing
* the characters, this method will throw an
* IOException wrapped in a SAXException
*/
private void writeEsc (char[] ch, int start, int length, boolean isAttVal)
throws SAXException {
for (int i = start; i < start + length; i++) {
switch (ch[i]) {
case '&':
write("&");
break;
case '<':
write("<");
break;
case '>':
write(">");
break;
case '\"':
if (isAttVal) {
write(""");
}
else {
write('\"');
}
break;
default:
if (ch[i] > '\u007f') {
write("&#");
write(Integer.toString(ch[i]));
write(';');
}
else {
write(ch[i]);
}
}
}
}
/**
* <p>
* Write an array of data characters without escaping.
* </p>
*
* @param ch the array of characters
* @param start the starting position
* @param length the number of characters to use
*
* @throws org.xml.SAXException if there is an error writing
* the characters, this method will throw an
* IOException wrapped in a SAXException.
*/
private void write(char[] ch, int start, int length)
throws SAXException {
try {
output.write(ch, start, length);
}
catch (IOException e) {
throw new SAXException(e);
}
}
/**
* <p>
* Write out the list of namespace declarations.
* </p>
*
* @throws org.xml.sax.SAXException This method will throw
* an IOException wrapped in a SAXException if
* there is an error writing the namespace
* declarations
*/
private void writeNSDecls() throws SAXException {
Enumeration prefixes = nsSupport.getDeclaredPrefixes();
while (prefixes.hasMoreElements()) {
String prefix = (String) prefixes.nextElement();
String uri = nsSupport.getURI(prefix);
if (uri == null) {
uri = "";
}
char[] ch = uri.toCharArray();
write(' ');
if ("".equals(prefix)) {
write("xmlns=\"");
}
else {
write("xmlns:");
write(prefix);
write("=\"");
}
writeEsc(ch, 0, ch.length, true);
write('\"');
}
}
/**
* <p>
* Write an element or attribute name.
* </p>
*
* @param uri the namespace URI
* @param localName the local name
* @param qualifiedName the prefixed name, if available,
* or the empty string.
* @param isElement true if this is an element name, false if it
* is an attribute name
*
* @throws org.xml.sax.SAXException this method will throw an
* IOException wrapped in a SAXException if there is
* an error writing the name
*/
private void writeName (String uri, String localName,
String qualifiedName, boolean isElement)
throws SAXException {
String prefix = doPrefix(uri, qualifiedName, isElement);
if (prefix != null && !"".equals(prefix)) {
write(prefix);
write(':');
}
write(localName);
}
////////////////////////////////////////////////////////////////////
// Constants.
////////////////////////////////////////////////////////////////////
private final Attributes EMPTY_ATTS = new AttributesImpl();
////////////////////////////////////////////////////////////////////
// Internal state.
////////////////////////////////////////////////////////////////////
private Hashtable prefixTable;
private Hashtable forcedDeclTable;
private Hashtable doneDeclTable;
private int elementLevel = 0;
private Writer output;
private NamespaceSupport nsSupport;
private int prefixCounter = 0;
///////////////////////////////////////////////////////////////////
// LexicalHandler methods.
///////////////////////////////////////////////////////////////////
public void endCDATA() {}
public void endDTD() throws SAXException {
write(">");
}
public void startCDATA() {}
public void comment(char[] ch, int start, int length)
throws SAXException {
write("<!--");
write(ch, start, length);
write("-->");
if (elementLevel < 1) {
write('\n');
}
}
public void endEntity(String name) {}
public void startEntity(String name) {}
public void startDTD(String name, String publicID, String systemID)
throws SAXException {
write("<!DOCTYPE ");
write(name);
if (systemID != null) {
if (publicID != null) {
write(" PUBLIC \"");
write(publicID);
write("\" \"");
write(systemID);
write("\"");
}
else {
write(" SYSTEM \"");
write(systemID);
write("\"");
}
}
}
}
// end of XMLWriter.java
|