com.hfg.xml.XMLEmitter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com_hfg Show documentation
Show all versions of com_hfg Show documentation
com.hfg xml, html, svg, and bioinformatics utility library
package com.hfg.xml;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.DefaultHandler;
import com.hfg.util.StringUtil;
//------------------------------------------------------------------------------
/**
@author J. Alex Taylor, hairyfatguy.com
*/
//------------------------------------------------------------------------------
public class XMLEmitter extends DefaultHandler implements LexicalHandler
{
//###########################################################################
// PUBLIC FIELDS
//###########################################################################
public static final int STYLE_COMPACT = 1;
public static final int STYLE_INDENTED = 2;
//###########################################################################
// PRIVATE FIELDS
//###########################################################################
private StringBuffer mCurrentData;
private StringBuffer mCurrentComment;
private int mPreviousTagType;
private int mCurrentIndent;
private XMLTag mDanglingStartTag;
private PrintWriter mWriter;
private int mPrintStyle = STYLE_COMPACT;
private int mIndentSize = 2;
private Stack mSafeToIndentStack = new Stack();
private boolean mSafeToIndent;
private static int START_TAG = 1;
private static int END_TAG = -1;
//###########################################################################
// CONSTRUCTORS
//###########################################################################
//---------------------------------------------------------------------------
/**
Default constructor - prints to System.out
*/
public XMLEmitter()
{
mWriter = new PrintWriter(System.out);
}
//---------------------------------------------------------------------------
/**
Prints XML to the specified stream
*/
public XMLEmitter(OutputStream inOutputStream)
{
mWriter = new PrintWriter(inOutputStream);
}
//---------------------------------------------------------------------------
/**
Prints XML to the specified stream
*/
public XMLEmitter(PrintWriter inWriter)
{
mWriter = inWriter;
}
//###########################################################################
// PUBLIC METHODS
//###########################################################################
//---------------------------------------------------------------------------
public void setPrintStyle(int inValue)
{
if (inValue < STYLE_COMPACT
|| inValue > STYLE_INDENTED)
{
throw new RuntimeException(inValue + " is not a valid print style!");
}
mPrintStyle = inValue;
}
//---------------------------------------------------------------------------
/**
Sets the number of spaces each tag level is indented
*/
public void setIndentSize(int inValue)
{
mIndentSize = inValue;
}
//---------------------------------------------------------------------------
public int getIndentSize()
{
return mIndentSize;
}
//---------------------------------------------------------------------------
public void startDocument()
{
mCurrentData = new StringBuffer();
mCurrentComment = new StringBuffer();
mPreviousTagType = END_TAG;
mCurrentIndent = -mIndentSize;
mSafeToIndentStack = new Stack();
mSafeToIndent = true;
}
//---------------------------------------------------------------------------
public void endDocument()
{
mWriter.flush();
}
//---------------------------------------------------------------------------
public void startElement(String uri, String local, String raw, Attributes attrs)
{
if (mDanglingStartTag != null)
{
emitStartTag(false);
if (mCurrentData.length() > 0)
{
emitContent();
}
}
List attributes = new ArrayList();
for (int i = 0; i < attrs.getLength(); i++)
{
attributes.add(new XMLAttribute(attrs.getQName(i), attrs.getValue(i)));
}
mDanglingStartTag = new XMLTag(raw, attributes);
/*
boolean safeToIndent = true;
if (mCurrentData.length() > 0)
{
if (mPrintStyle == STYLE_INDENTED)
{
safeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
if (safeToIndent)
{
mPrintStream.println();
mPrintStream.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mPrintStream.print(mCurrentData.toString());
if (mPrintStyle == STYLE_INDENTED && safeToIndent) mPrintStream.println();
}
List attributes = new ArrayList();
for (int i = 0; i < attrs.getLength(); i++)
{
attributes.add(new XMLAttribute(attrs.getQName(i), attrs.getValue(i)));
}
if (mPrintStyle == STYLE_INDENTED)
{
mCurrentIndent += mIndentSize;
mPrintStream.println();
mPrintStream.print(StringUtil.polyChar(' ', mCurrentIndent));
mPreviousTagType = START_TAG;
}
mPrintStream.print(XMLUtil.composeStartTag(raw, attributes));
mCurrentData = new StringBuffer();
*/
}
//---------------------------------------------------------------------------
public void endElement(String uri, String local, String raw)
{
/*
// Print any tag contents
if (mCurrentData.length() > 0)
{
if (mPrintStyle == STYLE_INDENTED)
{
safeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
if (safeToIndent)
{
mPrintStream.println();
mPrintStream.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mPrintStream.print(mCurrentData.toString());
if (mPrintStyle == STYLE_INDENTED && safeToIndent) mPrintStream.println();
}
else if (mPrintStyle == STYLE_INDENTED
&& mPreviousTagType == START_TAG)
{
mPrintStream.println();
}
mCurrentData = new StringBuffer();
*/
if (mDanglingStartTag != null
&& mCurrentData.length() == 0
&& mCurrentComment.length() == 0)
{
emitStartTag(true);
mDanglingStartTag = null;
}
else
{
if (mDanglingStartTag != null)
{
emitStartTag(false);
mDanglingStartTag = null;
}
/*
if (mCurrentComment.length() > 0)
{
emitComment();
}
*/
if (mCurrentData.length() > 0)
{
emitContent();
}
popIndentState();
// Write the end tag
if (mPrintStyle == STYLE_INDENTED)
{
if (mSafeToIndent)
{
mWriter.println();
// if (mPreviousTagType == END_TAG) mPrintStream.println();
mWriter.print(StringUtil.polyChar(' ', mCurrentIndent));
}
mCurrentIndent -= mIndentSize;
mPreviousTagType = END_TAG;
}
mWriter.print(XMLUtil.composeEndTag(raw));
}
}
//---------------------------------------------------------------------------
public void characters(char[] ch, int start, int length)
{
// System.out.print("In characters(): ");
/* if (mDanglingStartTag != null)
{
emitStartTag(false);
mDanglingStartTag = null;
}
*/
if (mCurrentData.length() > 0)
{
mCurrentData.append(ch, start, length);
if (mPrintStyle == STYLE_INDENTED
&& mSafeToIndent == true
&& mCurrentData.length() > 0)
{
mSafeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
}
if (mDanglingStartTag != null)
{
emitStartTag(false);
mDanglingStartTag = null;
}
emitContent();
}
else
{
mCurrentData.append(ch, start, length);
if (mPrintStyle == STYLE_INDENTED
&& mSafeToIndent == true
&& mCurrentData.length() > 0)
{
mSafeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
}
if (null == mDanglingStartTag)
{
emitContent();
}
}
/*
String content = new String(ch, start, length);
boolean safeToIndent = true;
// Print any tag contents
if (content.trim().length() > 0)
{
if (mPrintStyle == STYLE_INDENTED)
{
safeToIndent = contentLooksSafeToIndent(content);
if (safeToIndent)
{
mPrintStream.println();
mPrintStream.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mPrintStream.print(content);
// if (mPrintStyle == STYLE_INDENTED && safeToIndent) mPrintStream.println();
}
else if (mPrintStyle == STYLE_INDENTED
&& mPreviousTagType == START_TAG)
{
// mPrintStream.println();
}
*/
}
//---------------------------------------------------------------------------
public void warning(SAXParseException e)
{
e.printStackTrace();
}
//---------------------------------------------------------------------------
public void error(SAXParseException e)
{
e.printStackTrace();
}
//---------------------------------------------------------------------------
public void skippedEntity(String name)
throws SAXException
{
// System.out.println("In skippedEntity(): " + name);
}
//---------------------------------------------------------------------------
public void unparsedEntityDecl(String name,
String publicId,
String systemId,
String notationName)
throws SAXException
{
// System.out.println("In unparsedEntityDecl(): " + name);
}
// LexicalHandler methods
//--------------------------------------------------------------------------
public void comment(char[] inChars, int offset, int length)
{
// System.out.println("comment: '" + new String(inChars, offset, length) + "'");
if (mDanglingStartTag != null)
{
emitStartTag(false);
mDanglingStartTag = null;
}
if (mCurrentData.length() > 0)
{
emitContent();
}
// popIndentState();
mCurrentComment.append(inChars, offset, length);
emitComment();
/*
if (mCurrentComment.length() > 0)
{
mCurrentComment.append(inChars, offset, length);
if (mPrintStyle == STYLE_INDENTED
&& mSafeToIndent == true
&& mCurrentComment.length() > 0)
{
mSafeToIndent = contentLooksSafeToIndent(mCurrentComment.toString());
}
if (mDanglingStartTag != null)
{
emitStartTag(false);
mDanglingStartTag = null;
}
emitComment();
}
else
{
mCurrentComment.append(inChars, offset, length);
if (mPrintStyle == STYLE_INDENTED
&& mSafeToIndent == true
&& mCurrentComment.length() > 0)
{
mSafeToIndent = contentLooksSafeToIndent(mCurrentComment.toString());
}
if (null == mDanglingStartTag)
{
emitComment();
}
}
*/
}
//--------------------------------------------------------------------------
public void startCDATA()
{
}
//--------------------------------------------------------------------------
public void endCDATA()
{
}
//--------------------------------------------------------------------------
public void startEntity(String name)
{
}
//--------------------------------------------------------------------------
public void endEntity(String name)
{
}
//--------------------------------------------------------------------------
public void startDTD(String name, String publicId, String systemId)
{
}
//--------------------------------------------------------------------------
public void endDTD()
{
}
//---------------------------------------------------------------------------
// Tags like the HTML pre tag are sensitive to leading and trailing spaces.
private boolean contentLooksSafeToIndent(String inContent)
{
boolean response = true;
if (Character.isWhitespace(inContent.charAt(0))
|| Character.isWhitespace(inContent.charAt(inContent.length() - 1)))
{
response = false;
}
return response;
}
//---------------------------------------------------------------------------
private void emitStartTag(boolean inIsEmptyTag)
{
/*
if (mCurrentData.length() > 0)
{
if (mPrintStyle == STYLE_INDENTED)
{
safeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
if (safeToIndent)
{
mPrintStream.println();
mPrintStream.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mPrintStream.print(mCurrentData.toString());
// if (mPrintStyle == STYLE_INDENTED && safeToIndent) mPrintStream.println();
}
*/
if (mPrintStyle == STYLE_INDENTED)
{
mCurrentIndent += mIndentSize;
if (mSafeToIndentStack.size() == 0
|| ((Boolean) mSafeToIndentStack.peek()).booleanValue())
{
mWriter.println();
mWriter.print(StringUtil.polyChar(' ', mCurrentIndent));
}
if (inIsEmptyTag)
{
mCurrentIndent -= mIndentSize;
// mPreviousTagType = END_TAG;
}
else
{
mPreviousTagType = START_TAG;
pushIndentState();
mSafeToIndent = true;
}
}
mWriter.print(XMLUtil.composeStartTag(mDanglingStartTag.getTagName(),
mDanglingStartTag.getAttributes(),
inIsEmptyTag));
}
//---------------------------------------------------------------------------
private void emitContent()
{
if (mPrintStyle == STYLE_INDENTED)
{
if (mSafeToIndent)
{
// Re-evaluate
mSafeToIndent = contentLooksSafeToIndent(mCurrentData.toString());
}
if (mSafeToIndent)
{
mWriter.println();
mWriter.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mWriter.print(mCurrentData.toString());
mCurrentData.setLength(0);
}
//---------------------------------------------------------------------------
private void emitComment()
{
if (mPrintStyle == STYLE_INDENTED)
{
/*
if (mSafeToIndent)
{
// Re-evaluate
mSafeToIndent = contentLooksSafeToIndent(mCurrentComment.toString());
}
*/
mSafeToIndent = true;
if (mSafeToIndent)
{
mWriter.println();
mWriter.print(StringUtil.polyChar(' ', mCurrentIndent + mIndentSize));
}
}
mWriter.print("");
mCurrentComment.setLength(0);
}
//---------------------------------------------------------------------------
private void pushIndentState()
{
mSafeToIndentStack.push(new Boolean(mSafeToIndent));
}
//---------------------------------------------------------------------------
private void popIndentState()
{
mSafeToIndent = ((Boolean) mSafeToIndentStack.pop()).booleanValue();
}
}