/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2005 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution37.javolution.xml.sax;
import java.io.IOException;
import java.io.Writer;
import java.lang.CharSequence;
import javolution37.javolution.lang.Reusable;
import javolution37.javolution.lang.Text;
import javolution37.javolution.util.FastTable;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
/**
* This class generates xml documents from SAX2 events.
*
* @author Jean-Marie Dautelle
* @version 3.1, March 11, 2005
*/
public class WriterHandler implements ContentHandler, Reusable {
/**
* Holds the length of intermediate buffer.
*/
private static final int BUFFER_LENGTH = 2048;
/**
* Holds the writer destination.
*/
private Writer _writer;
/**
* Holds the prolog.
*/
private CharSequence _prolog = Text.EMPTY;
/**
* Holds the indentation string.
*/
private CharSequence _indent = Text.EMPTY;
/**
* Holds the current prefix mapping (prefix followed by uri).
*/
private FastTable _prefixMappings = new FastTable();
/**
* Holds the current nesting level.
*/
private int _nesting = -1;
/**
* Indicates if the current element tag is still open (to be closed
* with ">" or "/>" whether it is empty or not).
*/
private boolean _isTagOpen;
/**
* Holds intermediate buffer.
*/
private final char[] _buffer = new char[BUFFER_LENGTH];
/**
* Holds the buffer current index.
*/
private int _index;
/**
* Default constructor.
*/
public WriterHandler() {
}
/**
* Sets the xml document writer.
*
* @param writer the document writer.
* @return this
*/
public WriterHandler setWriter(Writer writer) {
_writer = writer;
return this;
}
/**
* Sets the indentation sequence (default none).
*
* @param indent a character sequence containing spaces or a tabulation character.
*/
public void setIndent(CharSequence indent) {
_indent = indent;
}
/**
* Sets the prolog to write at the beginning of the xml document
* (default none).
*
* @param prolog the character sequence to be written at the beginning
* of the document.
*/
public void setProlog(CharSequence prolog) {
_prolog = prolog;
}
// Implements reusable.
public void reset() {
_writer = null;
_indent = Text.EMPTY;
_prolog = Text.EMPTY;
_prefixMappings.clear();
_nesting = -1;
_isTagOpen = false;
_index = 0;
}
// Implements ContentHandler
public void setDocumentLocator(Locator locator) {
// Do nothing.
}
// Implements ContentHandler
public void startDocument() throws SAXException {
if (_writer == null)
throw new SAXException("Writer not set");
try {
writeNoEscape(_prolog);
} catch (IOException e) {
throw new SAXException(e);
}
}
// Implements ContentHandler
public void endDocument() throws SAXException {
try {
flushBuffer();
_writer.close();
} catch (IOException e) {
throw new SAXException(e);
}
}
// Implements ContentHandler
public void startPrefixMapping(CharSequence prefix, CharSequence uri)
throws SAXException {
_prefixMappings.addLast(prefix);
_prefixMappings.addLast(uri);
}
// Implements ContentHandler
public void endPrefixMapping(CharSequence prefix) throws SAXException {
// Do nothing.
}
// Implements ContentHandler
public void startElement(CharSequence uri, CharSequence localName,
CharSequence qName, Attributes atts) throws SAXException {
try {
if (_isTagOpen) { // The openned tag is not empty, close with ">"
writeNoEscape(">\n");
_isTagOpen = false;
}
// Indents.
_nesting++;
indent();
// Writes start tag.
writeNoEscape('<');
writeNoEscape(qName);
// Writes namespaces if any.
if (_prefixMappings.size() > 0) {
writeNamespaces();
}
// Writes attributes
final int attsLength = atts.getLength();
for (int i = 0; i < attsLength; i++) {
CharSequence attName = atts.getQName(i);
CharSequence attValue = atts.getValue(i);
writeNoEscape(' ');
writeNoEscape(attName);
writeNoEscape('=');
writeNoEscape('"');
write(attValue);
writeNoEscape('"');
}
_isTagOpen = true;
} catch (IOException e) {
throw new SAXException(e);
}
}
private void indent() throws IOException {
final int length = _indent.length();
if (length > 0) {
for (int i = 0; i < _nesting; i++) {
writeNoEscape(_indent);
}
}
}
private void writeNamespaces() throws IOException {
// Writes namespace declaration.
for (int i=0, length=_prefixMappings.size() ; i < length;) {
CharSequence prefix = (CharSequence) _prefixMappings.get(i++);
CharSequence prefixUri = (CharSequence) _prefixMappings.get(i++);
if (prefix.length() == 0) { // Default namespace.
writeNoEscape(" xmlns=\"");
write(prefixUri);
writeNoEscape('"');
} else {
writeNoEscape(" xmlns:");
writeNoEscape(prefix);
writeNoEscape('=');
writeNoEscape('"');
write(prefixUri);
writeNoEscape('"');
}
}
_prefixMappings.clear();
}
// Implements ContentHandler
public void endElement(CharSequence uri, CharSequence localName,
CharSequence qName) throws SAXException {
try {
if (_isTagOpen) { // The openned tag is empty, close with "/>"
writeNoEscape("/>\n");
_isTagOpen = false;
} else {
indent();
writeNoEscape('<');
writeNoEscape('/');
writeNoEscape(qName);
writeNoEscape('>');
writeNoEscape('\n');
}
_nesting--;
} catch (IOException e) {
throw new SAXException(e);
}
}
// Implements ContentHandler
public void characters(char[] ch, int start, int length)
throws SAXException {
try {
if (_isTagOpen) { // The openned tag is not empty, close with ">"
writeNoEscape('>');
_isTagOpen = false;
}
writeNoEscape("\n");
} catch (IOException e) {
throw new SAXException(e);
}
}
// Implements ContentHandler
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
// Do nothing.
}
// Implements ContentHandler
public void processingInstruction(CharSequence target, CharSequence data)
throws SAXException {
// Do nothing.
}
// Implements ContentHandler
public void skippedEntity(CharSequence name) throws SAXException {
// Do nothing.
}
// Writes the specified characters. Use escape sequence when necessary.
private void write(Object obj) throws IOException {
if (obj instanceof String) {
write((String)obj);
} else {
writeNonString((CharSequence)obj);
}
}
private void write(String str) throws IOException {
final int length = str.length();
for (int i = 0; i < length;) {
char c = str.charAt(i++);
if ((c >= '@') || (c == ' ')) { // Most common case.
_buffer[_index] = c;
if (++_index == BUFFER_LENGTH) {
flushBuffer();
}
} else { // Potential escape sequence.
switch (c) {
case '<':
writeNoEscape("<");
break;
case '>':
writeNoEscape(">");
break;
case '\'':
writeNoEscape("'");
break;
case '\"':
writeNoEscape(""");
break;
case '&':
writeNoEscape("&");
break;
default:
if (c >= ' ') {
writeNoEscape(c);
} else {
writeNoEscape("");
writeNoEscape((char) ('0' + c / 10));
writeNoEscape((char) ('0' + c % 10));
writeNoEscape(';');
}
}
}
}
}
private void writeNonString(CharSequence csq) throws IOException {
final int length = csq.length();
for (int i = 0; i < length;) {
char c = csq.charAt(i++);
if ((c >= '@') || (c == ' ')) { // Most common case.
_buffer[_index] = c;
if (++_index == BUFFER_LENGTH) {
flushBuffer();
}
} else { // Potential escape sequence.
switch (c) {
case '<':
writeNoEscape("<");
break;
case '>':
writeNoEscape(">");
break;
case '\'':
writeNoEscape("'");
break;
case '\"':
writeNoEscape(""");
break;
case '&':
writeNoEscape("&");
break;
default:
if (c >= ' ') {
writeNoEscape(c);
} else {
writeNoEscape("");
writeNoEscape((char) ('0' + c / 10));
writeNoEscape((char) ('0' + c % 10));
writeNoEscape(';');
}
}
}
}
}
private void writeNoEscape(Object obj) throws IOException {
if (obj instanceof String) {
writeNoEscape((String)obj);
} else {
writeNoEscapeNonString((CharSequence)obj);
}
}
private void writeNoEscape(String str) throws IOException {
for (int i = 0, n = str.length(); i < n;) {
_buffer[_index] = str.charAt(i++);
if (++_index == BUFFER_LENGTH) {
flushBuffer();
}
}
}
private void writeNoEscapeNonString(CharSequence csq) throws IOException {
for (int i = 0, n = csq.length(); i < n;) {
_buffer[_index] = csq.charAt(i++);
if (++_index == BUFFER_LENGTH) {
flushBuffer();
}
}
}
private final void writeNoEscape(char c) throws IOException {
_buffer[_index] = c;
if (++_index == BUFFER_LENGTH) {
flushBuffer();
}
}
private void flushBuffer() throws IOException {
_writer.write(_buffer, 0, _index);
_index = 0;
}
}
Ads help maintain this website.