[jsword-svn] common/java/core/org/crosswire/common/xml s

jswordcvs at crosswire.org jswordcvs at crosswire.org
Sat Mar 12 14:15:57 MST 2005


Update of /cvs/jsword/common/java/core/org/crosswire/common/xml
In directory www.crosswire.org:/tmp/cvs-serv1368/java/core/org/crosswire/common/xml

Modified Files:
	XMLUtil.java 
Added Files:
	HTMLSerializingContentHandler.java 
	PrettySerializingContentHandler.java FormatType.java 
Log Message:
Jira BD-28. Tidy and syntax highlighting of View Source.

--- NEW FILE: HTMLSerializingContentHandler.java ---
package org.crosswire.common.xml;

import java.io.Writer;

/**
 * This class provides for the formatted and syntax highlighted
 * serialization of a SAX stream to a <code>Writer</code>.
 *
 * <p><table border='1' cellPadding='3' cellSpacing='0'>
 * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
 *
 * Distribution Licence:<br />
 * JSword is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public License,
 * version 2 as published by the Free Software Foundation.<br />
 * This program 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
 * General Public License for more details.<br />
 * The License is available on the internet
 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA<br />
 * The copyright to this program is held by it's authors.
 * </font></td></tr></table>
 * @see gnu.gpl.Licence
 * @author DM Smith [ dmsmith555 at gmail dot com]
 * @version $Id: HTMLSerializingContentHandler.java,v 1.1 2005/03/12 21:15:55 dmsmith Exp $
 */
public class HTMLSerializingContentHandler extends PrettySerializingContentHandler
{

    /**
     * A formatting serializer that does not add whitespace to the document.
     * This uses a StringWriter and the toString method will return its content.
     */
    public HTMLSerializingContentHandler()
    {
        super();
    }

    /**
     * A formatting serializer that adds whitespace to the document
     * according to the specified <code>FormatType</code>. This uses
     * a StringWriter and the toString method will return its content.
     * 
     * @param theFormat the formatting to use
     */
    public HTMLSerializingContentHandler(FormatType theFormat)
    {
        super(theFormat);
    }

    /**
     * A formatting serializer that adds whitespace to the document
     * according to the specified <code>FormatType</code>. As the document
     * is serialized it is written to the provided <code>Writer</code>.
     * 
     * @param theFormat the formatting to use
     * @param theWriter the writer to use
     */
    public HTMLSerializingContentHandler(FormatType theFormat, Writer theWriter)
    {
        super(theFormat, theWriter);
    }

    protected String decorateTagName(String tagName)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("<font class='tag'>"); //$NON-NLS-1$
        buf.append(super.decorateTagName(tagName));
        buf.append("</font>"); //$NON-NLS-1$
        return buf.toString();
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#decorateAttributeName(java.lang.String)
     */
    protected String decorateAttributeName(String attrName)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("<font class='attr'>"); //$NON-NLS-1$
        buf.append(super.decorateAttributeName(attrName));
        buf.append("</font>"); //$NON-NLS-1$
        return buf.toString();
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#decorateAttributeValue(java.lang.String)
     */
    protected String decorateAttributeValue(String attrValue)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("<font class='value'>"); //$NON-NLS-1$
        buf.append(super.decorateAttributeValue(attrValue));
        buf.append("</font>"); //$NON-NLS-1$
        return buf.toString();
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#decorateCharacters(java.lang.String)
     */
    protected String decorateCharacters(String characters)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("<font class='text'>"); //$NON-NLS-1$
        buf.append(XMLUtil.escape(super.decorateCharacters(characters)).replaceAll("\n", "<br>")); //$NON-NLS-1$ //$NON-NLS-2$
        buf.append("</font>"); //$NON-NLS-1$
        return buf.toString();
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#decorateIndent(int)
     */
    protected String decorateIndent(int indentLevel)
    {
        StringBuffer buf = new StringBuffer();
        buf.append("<font class='indent'>"); //$NON-NLS-1$
        buf.append(super.decorateIndent(indentLevel).replaceAll("\t","&nbsp;&nbsp;&nbsp;&nbsp;")); //$NON-NLS-1$ //$NON-NLS-2$
        buf.append("</font>"); //$NON-NLS-1$
        return buf.toString();
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#startDocument()
     */
    public void startDocument()
    {
        StringBuffer buf = new StringBuffer();
        // Note: we should be using SPAN here but Sun's Java does not support styling it.
        // Also, it introduces whitespace between the span and the text.
        buf.append("FONT.tag    { color : #666699; font-weight: bold; }\n"); //$NON-NLS-1$
        buf.append("FONT.attr   { color : #669966; font-weight: bold; }\n"); //$NON-NLS-1$
        buf.append("FONT.value  { color : #669966; font-style: italic; }\n"); //$NON-NLS-1$
        buf.append("FONT.indent { }\n"); //$NON-NLS-1$
        buf.append("FONT.text   { background : yellow; }\n"); //$NON-NLS-1$
        write("<html><head><style type='text/css'>\n"); //$NON-NLS-1$
        write(buf.toString());
        write("</style></head><body>\n"); //$NON-NLS-1$
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#endDocument()
     */
    public void endDocument()
    {
        write("</body></head>"); //$NON-NLS-1$
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getEmptyTagEnd()
     */
    protected String getEmptyTagEnd()
    {
        return XMLUtil.escape(super.getEmptyTagEnd());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getEndTagStart()
     */
    protected String getEndTagStart()
    {
        return XMLUtil.escape(super.getEndTagStart());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getPIEnd()
     */
    protected String getPIEnd()
    {
        return XMLUtil.escape(super.getPIEnd());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getPIStart()
     */
    protected String getPIStart()
    {
        return XMLUtil.escape(super.getPIStart());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getTagEnd()
     */
    protected String getTagEnd()
    {
        return XMLUtil.escape(super.getTagEnd());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getTagStart()
     */
    protected String getTagStart()
    {
        return XMLUtil.escape(super.getTagStart());
    }

    /* (non-Javadoc)
     * @see org.crosswire.common.xml.PrettySerializingContentHandler#getNewline()
     */
    protected String getNewline()
    {
        return "<br>"; //$NON-NLS-1$
    }
}

--- NEW FILE: FormatType.java ---
package org.crosswire.common.xml;

import java.io.Serializable;


/**
 * The PrettySerializingContentHandler uses a FormatType to control its output.
 * 
 * <p><table border='1' cellPadding='3' cellSpacing='0'>
 * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
 *
 * Distribution Licence:<br />
 * JSword is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public License,
 * version 2 as published by the Free Software Foundation.<br />
 * This program 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
 * General Public License for more details.<br />
 * The License is available on the internet
 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA<br />
 * The copyright to this program is held by it's authors.
 * </font></td></tr></table>
 * @see gnu.gpl.Licence
 * @author DM Smith [dmsmith555 at gmail dot com]
 * @version $Id: FormatType.java,v 1.1 2005/03/12 21:15:55 dmsmith Exp $
 */
public final class FormatType implements Serializable
{
    public static final FormatType AS_IS            = new FormatType("AS_IS", false, false, false); //$NON-NLS-1$
    public static final FormatType ANALYSIS         = new FormatType("ANALYSIS", true, false, false); //$NON-NLS-1$
    public static final FormatType CLASSIC          = new FormatType("CLASSIC", true, false, true); //$NON-NLS-1$
    public static final FormatType ANALYSIS_INDENT  = new FormatType("ANALYSIS_INDENT", true, true, false); //$NON-NLS-1$
    public static final FormatType CLASSIC_INDENT   = new FormatType("CLASSIC_INDENT", true, true, true); //$NON-NLS-1$

    /**
     * Simple ctor
     */
    public FormatType(String aName, boolean displayNewlines, boolean doIndenting, boolean classicLines)
    {
        name = aName;
        multiline = displayNewlines;
        // the following are true only if we add newlines.
        indented = doIndenting && multiline;
        classic = classicLines && multiline;
        analytic = !classicLines && multiline;
    }

    /**
     * Whether newlines are introduced into the document.
     * @return true if newlines are added to the document
     */
    public boolean isMultiline()
    {
        return multiline;
    }
    
    /**
     * Whether indents are introduced into the document.
     * @return true if indents are added to the document
     */
    public boolean isIndented()
    {
        return indented;
    }

    /**
     * Whether added whitespace is inside tags. Note, this does
     * not change the document.
     * @return true if whitespace is added inside tags of document
     */
    public boolean isAnalytic()
    {
        return analytic;
    }
    
    /**
     * Whether added whitespace is between tags. Note, this does
     * change the document as whitespace is added to either side of
     * existing text.
     * @return true if whitespace is added inside tags of document
     */
    public boolean isClassic()
    {
        return classic;
    }

    /**
     * Get an integer representation for this FormatType
     */
    public int toInteger()
    {
        for (int i = 0; i < VALUES.length; i++)
        {
            if (equals(VALUES[i]))
            {
                return i;
            }
        }
        // cannot get here
        assert false;
        return -1;
    }

    /**
     * Lookup method to convert from a String
     */
    public static FormatType fromString(String name)
    {
        for (int i = 0; i < VALUES.length; i++)
        {
            FormatType obj = VALUES[i];
            if (obj.name.equalsIgnoreCase(name))
            {
                return obj;
            }
        }
        // cannot get here
        assert false;
        return null;
    }

    /**
     * Lookup method to convert from an integer
     */
    public static FormatType fromInteger(int i)
    {
        return VALUES[i];
    }

    /**
     * Prevent subclasses from overriding canonical identity based Object methods
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public final boolean equals(Object o)
    {
        return super.equals(o);
    }

    /**
     * Prevent subclasses from overriding canonical identity based Object methods
     * @see java.lang.Object#hashCode()
     */
    public final int hashCode()
    {
        return super.hashCode();
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        return name;
    }

    /**
     * The name of the FormatType
     */
    private String name;
    private boolean indented;
    private boolean multiline;
    private boolean analytic;
    private boolean classic;

    // Support for serialization
    private static int nextObj;
    private final int obj = nextObj++;

    Object readResolve()
    {
        return VALUES[obj];
    }

    private static final FormatType[] VALUES =
    {
        AS_IS,
        ANALYSIS,
        CLASSIC,
        ANALYSIS_INDENT,
        CLASSIC_INDENT,
    };

    /**
     * Serialization ID
     */
    private static final long serialVersionUID = 3544385916136142129L;
}

--- NEW FILE: PrettySerializingContentHandler.java ---
package org.crosswire.common.xml;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;

/**
 * This class provides for the formatted serialization of a SAX stream
 * to a <code>Writer</code>.
 *
 * <p><table border='1' cellPadding='3' cellSpacing='0'>
 * <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
 *
 * Distribution Licence:<br />
 * JSword is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General Public License,
 * version 2 as published by the Free Software Foundation.<br />
 * This program 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
 * General Public License for more details.<br />
 * The License is available on the internet
 * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA<br />
 * The copyright to this program is held by it's authors.
 * </font></td></tr></table>
 * @see gnu.gpl.Licence
 * @author DM Smith [dmsmith555 at gmail dot com]
 * @version $Id: PrettySerializingContentHandler.java,v 1.1 2005/03/12 21:15:55 dmsmith Exp $
 */
public class PrettySerializingContentHandler implements ContentHandler
{
    /**
     * A formatting serializer that does not add whitespace to the document.
     * This uses a StringWriter and the toString method will return its content.
     */
    public PrettySerializingContentHandler()
    {
        this(FormatType.AS_IS);
    }

    /**
     * A formatting serializer that adds whitespace to the document
     * according to the specified <code>FormatType</code>. This uses
     * a StringWriter and the toString method will return its content.
     * 
     * @param theFormat the formatting to use
     */
    public PrettySerializingContentHandler(FormatType theFormat)
    {
        this(theFormat, null);
    }

    /**
     * A formatting serializer that adds whitespace to the document
     * according to the specified <code>FormatType</code>. As the document
     * is serialized it is written to the provided <code>Writer</code>.
     * 
     * @param theFormat the formatting to use
     * @param theWriter the writer to use
     */
    public PrettySerializingContentHandler(FormatType theFormat, Writer theWriter)
    {
        formatting = theFormat;
        writer = theWriter == null ? new StringWriter() : theWriter;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        return writer.toString();
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
     */
    public void setDocumentLocator(Locator locator)
    {
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#startDocument()
     */
    public void startDocument()
    {
        //write("<?xml version=\"1.0\"?>");
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#endDocument()
     */
    public void endDocument()
    {
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
     */
    public void startPrefixMapping(String prefix, String uri)
    {
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
     */
    public void endPrefixMapping(String prefix)
    {
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(String uri, String localname, String qname, Attributes attrs)
    {
        if (depth > 0)
        {
            handlePending();
        }

        write(getTagStart());
        write(decorateTagName(localname));

        for (int i = 0; i < attrs.getLength(); i++)
        {
            write(' ');
            write(decorateAttributeName(attrs.getLocalName(i)));
            write("='"); //$NON-NLS-1$
            write(decorateAttributeValue(XMLUtil.escape(attrs.getValue(i))));
            write('\'');
        }

        pendingEndTag = true;
        depth++;
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(String uri, String localname, String qname)
    {
        depth--;
        if (pendingEndTag)
        {
            if (formatting.isAnalytic() && depth > 0)
            {
                emitWhitespace(depth - 1);
            }

            write(getEmptyTagEnd());
        }
        else
        {
            if (formatting.isClassic())
            {
                emitWhitespace(depth);
            }

            write(getEndTagStart());

            write(decorateTagName(localname));

            if (formatting.isAnalytic())
            {
                emitWhitespace(depth);
            }

            write(getTagEnd());
        }
        pendingEndTag = false;
        lookingForChars = false;
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
     */
    public void characters(char[] chars, int start, int length)
    {
        if (!lookingForChars)
        {
            handlePending();
        }

        String s = new String(chars, start, length);
        write(decorateCharacters(s));
        lookingForChars = true;
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
     */
    public void ignorableWhitespace(char[] chars, int start, int length)
    {
        characters(chars, start, length);
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
     */
    public void processingInstruction(String target, String data)
    {
        handlePending();

        write(getPIStart());
        write(target);
        write(' ');
        write(decorateCharacters(data));
        write(getPIEnd());

        if (formatting.isMultiline())
        {
            write(getNewline());
        }
    }

    /* (non-Javadoc)
     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
     */
    public void skippedEntity(String name)
    {
    }

    protected String getTagStart()
    {
        return "<"; //$NON-NLS-1$
    }

    protected String getTagEnd()
    {
        return ">"; //$NON-NLS-1$
    }

    protected String getEmptyTagEnd()
    {
        return "/>"; //$NON-NLS-1$
    }

    protected String getEndTagStart()
    {
        return "</"; //$NON-NLS-1$
    }
    
    protected String getPIStart()
    {
        return "<!"; //$NON-NLS-1$
    }

    protected String getPIEnd()
    {
        return "!>"; //$NON-NLS-1$
    }

    protected String getNewline()
    {
        return "\n"; //$NON-NLS-1$
    }

    protected String decorateTagName(String tagName)
    {
        return tagName;
    }

    protected String decorateAttributeName(String attrName)
    {
        return attrName;
    }
    
    protected String decorateAttributeValue(String attrValue)
    {
        return attrValue;
    }
    
    protected String decorateCharacters(String characters)
    {
        return characters;
    }
    
    protected String decorateIndent(int indentLevel)
    {
        return new String(indentation, 0, indentLevel).intern();
    }
    
    protected void write(String obj)
    {
        try
        {
            writer.write(obj);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    protected void write(char obj)
    {
        try
        {
            writer.write(obj);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private void handlePending()
    {
        if (pendingEndTag)
        {
            pendingEndTag = false;

            if (formatting.isAnalytic())
            {
                emitWhitespace(depth);
            }

            write(getTagEnd());

        }
        if (formatting.isClassic())
        {
            emitWhitespace(depth);
        }
        lookingForChars = false;
    }
    
    private void emitWhitespace(int indentLevel)
    {
        write(getNewline());
        if (formatting.isIndented())
        {
            write(decorateIndent(indentLevel));
        }
    }
    
    /**
     * This allows for rapid output of whitespace.
     */
    static private char[] indentation =
    {
        '\t', '\t', '\t', '\t', '\t',
        '\t', '\t', '\t', '\t', '\t',
        '\t', '\t', '\t', '\t', '\t',
        '\t', '\t', '\t', '\t', '\t',
        '\t', '\t', '\t', '\t', '\t',
        '\t', '\t', '\t', '\t', '\t'
    };

    /**
     * The depth is incremented on each startElement and decremented on each endElement.
     * This is used to output the indentation.
     */
    private int depth;

    /**
     * It is possible that characters(...) will be called for adjacent pieces of text.
     * Often this is due to entities in the text. This will allow for these to be
     * joined back together.
     */
    private boolean lookingForChars;

    /**
     * One of the difficulties in SAX parsing is that it does not retain state.
     * Even for an empty tag, it calls startElement and endElement. This allows
     * for making empty elements to have the empty tag notation: &lt;tag/&gt;.
     */
    private boolean pendingEndTag;

    private FormatType formatting;

    private Writer writer;
}

Index: XMLUtil.java
===================================================================
RCS file: /cvs/jsword/common/java/core/org/crosswire/common/xml/XMLUtil.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** XMLUtil.java	28 Feb 2005 02:21:30 -0000	1.8
--- XMLUtil.java	12 Mar 2005 21:15:55 -0000	1.9
***************
*** 11,14 ****
--- 11,15 ----
  import org.jdom.input.SAXBuilder;
  import org.xml.sax.Attributes;
+ import org.xml.sax.ContentHandler;
  import org.xml.sax.SAXException;
  
***************
*** 71,75 ****
      public static String writeToString(SAXEventProvider provider) throws SAXException
      {
!         SerializingContentHandler ser = new SerializingContentHandler();
          provider.provideSAXEvents(ser);
          return ser.toString();
--- 72,76 ----
      public static String writeToString(SAXEventProvider provider) throws SAXException
      {
!         ContentHandler ser = new PrettySerializingContentHandler();
          provider.provideSAXEvents(ser);
          return ser.toString();
***************
*** 348,352 ****
  
              // So we have the end of the tag, delete it ...
!             //DataPolice.report("disguarding tag: " + working.substring(lt, i + 1));
              working = working.substring(0, lt) + working.substring(i + 1);
          }
--- 349,353 ----
  
              // So we have the end of the tag, delete it ...
!             //DataPolice.report("discarding tag: " + working.substring(lt, i + 1));
              working = working.substring(0, lt) + working.substring(i + 1);
          }



More information about the jsword-svn mailing list