sandbox/src/net/sf/xframe/sax SimpleSAXWriter.java,NONE,1.1

Kurt Riede <[email protected]> Mon, 21 Mar 2005 18:13:24 +0000
Newsgroups gmane.text.xml.xframe.xsddoc.devel
Message-ID <[email protected]>
Update of /cvsroot/xframe/sandbox/src/net/sf/xframe/sax
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27005/src/net/sf/xframe/sax

Added Files:
	SimpleSAXWriter.java 
Log Message:
initial upload of classes for working with XSModel classes of Apache XercesJ 2.6.2

--- NEW FILE: SimpleSAXWriter.java ---
/*
This file is part of the xframe software package
hosted at http://xframe.sourceforge.net

Copyright (c) 2003 Kurt Riede.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package net.sf.xframe.sax;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Method;

import net.sf.xframe.xs.parser.AttributesImpl;

import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.DefaultHandler;

/**
 * A simple SAX2 writer.
 *
 * @author <a href="mailto:[email protected]">Kurt Riede</a>
 */
public final class SimpleSAXWriter extends DefaultHandler implements LexicalHandler {

    /** Print writer. */
    private PrintWriter fOut = null;

    /** Encoding used for writing. */
    private String fEncoding = "UTF-8";

    /** Canonical output. */
    private boolean fCanonical = true;

    /** Element depth. */
    private int fElementDepth = 0;

    /** Document locator. */
    private Locator fLocator = null;

    /** Processing XML 1.1 document. */
    private boolean fXML11 = false;

    /** In CDATA section. */
    private boolean fInCDATA = false;

    /** Reference to an error handler. */
    private ErrorHandler errorHandler = new ConsoleErrorHandler();

    /** Default constructor. */
    public SimpleSAXWriter() {
    }

    /**
     * Constructor.
     * @param writer the output writer
     */
    public SimpleSAXWriter(final Writer writer) {
        setOutput(writer);
    }

    /**
     * Constructor.
     * @param stream the output stream
     * @param encoding the output encoding
     * @throws UnsupportedEncodingException if the requested encoding is not supported
     */
    public SimpleSAXWriter(final OutputStream stream, final String encoding) throws UnsupportedEncodingException {
        setOutput(stream, encoding);
    }

    /**
     * Sets whether output is canonical.
     * @param canonical if output shsould be canonical or not.
     */
    public void setCanonical(final boolean canonical) {
        fCanonical = canonical;
    }

    /**
     * Sets the output stream for printing.
     * @param stream the output stream
     * @param encoding the output encoding
     * @throws UnsupportedEncodingException if the requested encoding is not supported
     */
    public void setOutput(final OutputStream stream, final String encoding) throws UnsupportedEncodingException {
        final Writer writer = new OutputStreamWriter(stream, encoding == null ? "UTF8" : encoding);
        fOut = new PrintWriter(writer);
        fEncoding = encoding;
    }

    /**
     * Sets the output writer for printing.
     * @param writer the output writer
     */
    public void setOutput(final Writer writer) {
        fOut = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer);
    }

    /**
     * @see org.xml.sax.DefaultHandler#setDocumentLocator()
     */
    public void setDocumentLocator(final Locator locator) {
        fLocator = locator;
    }

    /**
     * @see org.xml.sax.ContentHandler#startDocument()
     */
    public void startDocument() throws SAXException {
        fElementDepth = 0;
        fXML11 = false;
        fInCDATA = false;
    }

    /**
     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
     */
    public void processingInstruction(final String target, final String data) throws SAXException {
        if (fElementDepth > 0) {
            fOut.print("<?");
            fOut.print(target);
            if (data != null && data.length() > 0) {
                fOut.print(' ');
                fOut.print(data);
            }
            fOut.print("?>");
            fOut.flush();
        }
    }

    /**
     * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
     *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(final String uri, final String local, final String raw, final Attributes attrsUnsorted)
            throws SAXException {
        if (fElementDepth == 0) {
            if (fLocator != null) {
                fXML11 = "1.1".equals(getVersion());
                fLocator = null;
            }
            if (!fCanonical) {
                if (fXML11) {
                    fOut.println("<?xml version=\"1.1\" encoding=\"" + fEncoding + "\"?>");
                } else {
                    fOut.println("<?xml version=\"1.0\" encoding=\"" + fEncoding + "\"?>");
                }
                fOut.flush();
            }
        }
        fElementDepth++;
        fOut.print('<');
        fOut.print(raw);
        if (attrsUnsorted != null) {
            final Attributes attrs = sortAttributes(attrsUnsorted);
            final int len = attrs.getLength();
            for (int i = 0; i < len; i++) {
                fOut.print(' ');
                fOut.print(attrs.getQName(i));
                fOut.print("=\"");
                normalizeAndPrint(attrs.getValue(i), true);
                fOut.print('"');
            }
        }
        fOut.print('>');
        fOut.flush();
    }

    /**
     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
     */
    public void characters(final char[] ch, final int start, final int length) throws SAXException {
        if (!fInCDATA) {
            normalizeAndPrint(ch, start, length, false);
        } else {
            for (int i = 0; i < length; ++i) {
                fOut.print(ch[start + i]);
            }
        }
        fOut.flush();

    }

    /**
     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
     */
    public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException {
        characters(ch, start, length);
        fOut.flush();
    }

    /**
     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(final String uri, final String local, final String raw) throws SAXException {
        fElementDepth--;
        fOut.print("</");
        fOut.print(raw);
        fOut.print('>');
        fOut.flush();
    }

    /**
     * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
     */
    public void warning(final SAXParseException e) throws SAXException {
        errorHandler.warning(e);
    }

    /**
     * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
     */
    public void error(final SAXParseException e) throws SAXException {
        errorHandler.error(e);
    }

    /**
     * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
     */
    public void fatalError(final SAXParseException e) throws SAXException {
        errorHandler.fatalError(e);
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#startDTD()
     */
    public void startDTD(final String name, final String publicId, final String systemId) throws SAXException {
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#endDTD()
     */
    public void endDTD() throws SAXException {
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String)
     */
    public void startEntity(final String arg0) throws SAXException {
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String)()
     */
    public void endEntity(final String name) throws SAXException {
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#startCDATA()
     */
    public void startCDATA() throws SAXException {
        if (!fCanonical) {
            fOut.print("<![CDATA[");
            fInCDATA = true;
        }
    }

    /**
     * @throws SAXException s
     */
    public void endCDATA() throws SAXException {
        if (!fCanonical) {
            fInCDATA = false;
            fOut.print("]]>");
        }
    }

    /**
     * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
     */
    public void comment(final char[] ch, final int start, final int length) throws SAXException {
        if (!fCanonical && fElementDepth > 0) {
            fOut.print("<!--");
            for (int i = 0; i < length; ++i) {
                fOut.print(ch[start + i]);
            }
            fOut.print("-->");
            fOut.flush();
        }
    }

    /** Returns a sorted list of attributes. */
    private Attributes sortAttributes(final Attributes attrs) {
        final AttributesImpl attributes = new AttributesImpl();
        final int len = (attrs != null) ? attrs.getLength() : 0;
        for (int i = 0; i < len; i++) {
            final String name = attrs.getQName(i);
            final int count = attributes.getLength();
            int j = 0;
            while (j < count) {
                if (name.compareTo(attributes.getQName(j)) < 0) {
                    break;
                }
                j++;
            }
            attributes.insertAttributeAt(j, name, attrs.getType(i), attrs.getValue(i));
        }
        return attributes;

    }

    /** Normalizes and prints the given string. */
    private void normalizeAndPrint(final String s, final boolean isAttValue) {
        final int len = (s != null) ? s.length() : 0;
        for (int i = 0; i < len; i++) {
            normalizeAndPrint(s.charAt(i), isAttValue);
        }
    }

    /** Normalizes and prints the given array of characters. */
    private void normalizeAndPrint(final char[] ch, final int offset, final int length, final boolean isAttValue) {
        for (int i = 0; i < length; i++) {
            normalizeAndPrint(ch[offset + i], isAttValue);
        }
    }

    /** Normalizes and print the given character. */
    private void normalizeAndPrint(final char c, final boolean isAttValue) {
        switch (c) {
        case '<':
            fOut.print("&lt;");
            break;
        case '>':
            fOut.print("&gt;");
            break;
        case '&':
            fOut.print("&amp;");
            break;
        case '"':
            // A '"' that appears in character data
            // does not need to be escaped.
            if (isAttValue) {
                fOut.print("&quot;");
            } else {
                fOut.print("\"");
            }
            break;
        case '\r':
            // If CR is part of the document's content, it
            // must not be printed as a literal otherwise
            // it would be normalized to LF when the document
            // is reparsed.
            fOut.print("&#xD;");
            break;
        case '\n':
            if (fCanonical) {
                fOut.print("&#xA;");
                break;
            }
        default:
            // In XML 1.1, control chars in the ranges [#x1-#x1F, #x7F-#x9F] must be escaped.
            //
            // Escape space characters that would be normalized to #x20 in
            // attribute values when the document is reparsed.
            //
            // Escape NEL (0x85) and LSEP (0x2028) that appear in content
            // if the document is XML 1.1, since they would be normalized to LF
            // when the document is reparsed.
            if (fXML11
                    && ((c >= ASCII.SOH && c <= ASCII.US && c != ASCII.TAB && c != ASCII.LF)
                            || (c >= ASCII.DEL && c <= ASCII.OA) || c == ASCII.LSEP) || isAttValue
                    && (c == ASCII.TAB || c == ASCII.LF)) {
                fOut.print("&#x");
                fOut.print(Integer.toHexString(c).toUpperCase());
                fOut.print(";");
            } else {
                fOut.print(c);
            }
        }
    }

    /**
     * Some character constants that are relevant for proper encoding.
     */
    private class ASCII {

        /** Start of heading. */
        private static final char SOH = 0x01;

        /** Unit Seperator. */
        private static final char US = 0x1F;

        /** Tabulator. */
        private static final char TAB = 0x09;

        /** Line Feed. */
        private static final char LF = 0x0A;

        /** Delete. */
        private static final char DEL = 0x7F;

        /** small o with accent egu. */
        private static final char OA = 0x9F;

        /** Unicode line seperator. */
        private static final char LSEP = 0x2028;
    }

    /**
     * Console error handler (outputs all errors to the console error stream).
     */
    private class ConsoleErrorHandler implements ErrorHandler {

        /**
         * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
         */
        public void warning(final SAXParseException e) throws SAXException {
            printError("Warning", e);
        }

        /**
         * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
         */
        public void error(final SAXParseException e) throws SAXException {
            printError("Error", e);
        }

        /**
         * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
         */
        public void fatalError(final SAXParseException e) throws SAXException {
            printError("Fatal Error", e);
            throw e;
        }

        /** Prints the error message. */
        private void printError(final String type, final SAXParseException ex) {
            System.err.print("[");
            System.err.print(type);
            System.err.print("] ");
            String systemId = ex.getSystemId();
            if (systemId != null) {
                int index = systemId.lastIndexOf('/');
                if (index != -1) {
                    systemId = systemId.substring(index + 1);
                }
                System.err.print(systemId);
            }
            System.err.print(':');
            System.err.print(ex.getLineNumber());
            System.err.print(':');
            System.err.print(ex.getColumnNumber());
            System.err.print(": ");
            System.err.print(ex.getMessage());
            System.err.println();
            System.err.flush();
        }
    }

    /** Extracts the XML version from the Locator. */
    private String getVersion() {
        if (fLocator == null) {
            return null;
        }
        try {
            final Method getXMLVersion = fLocator.getClass().getMethod("getXMLVersion", new Class[] {});
            // If Locator implements Locator2, this method will exist.
            if (getXMLVersion != null) {
                return (String) getXMLVersion.invoke(fLocator, null);
            }
        } catch (Exception e) {
            return null;
            // Either this locator object doesn't have
            // this method, or we're on an old JDK.
        }
        return null;
    }
}



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click