import com.jclark.xsl.sax.*; import java.io.*; import org.xml.sax.*; import java.util.Hashtable; public class StructXMLOutputHandler implements OutputDocumentHandler, CommentHandler, RawCharactersHandler { private Writer writer; private char maxRepresentableChar = '\uFFFF'; private boolean keepOpen; private boolean inStartTag = false; private boolean omitXmlDeclaration = false; private String standalone; private static final int DEFAULT_BUF_LENGTH = 8*1024; private char[] buf = new char[DEFAULT_BUF_LENGTH]; private int bufUsed = 0; private String lineSeparator; private byte minimize = MINIMIZE_EMPTY_ELEMENTS; private String doctypeSystem; private String doctypePublic; private boolean outputDoctype = false; private String encoding ; // Struct private String structNsPrefix = null ; private int structNsPrefixSize = 0 ; Destination dest; AttributeList initAtts; static final public byte MINIMIZE_NONE = 0; static final public byte MINIMIZE_EMPTY_ELEMENTS = 1; static final public byte MINIMIZE_EMPTY_ELEMENTS_HTML = 2; public StructXMLOutputHandler() { lineSeparator = System.getProperty("line.separator"); } public StructXMLOutputHandler(Writer writer) { this.writer = writer; } public DocumentHandler init(Destination dest, AttributeList atts) throws IOException { this.dest = dest; initAtts = atts; if ("yes".equals(atts.getValue("indent"))) return new Indenter(this, this); return this; } void initWriter() throws IOException { String mediaType = initAtts.getValue("media-type"); if (mediaType == null) mediaType = "text/xml"; if (encoding == null) { // not all Java implementations support ASCII writer = dest.getWriter(mediaType, "iso-8859-1"); // use character references for non-ASCII characters maxRepresentableChar = '\u007F'; } else { writer = dest.getWriter(mediaType, encoding); encoding = dest.getEncoding(); if (encoding.equalsIgnoreCase("iso-8859-1")) maxRepresentableChar = '\u00FF'; else if (encoding.equalsIgnoreCase("us-ascii")) maxRepresentableChar = '\u007F'; } this.keepOpen = dest.keepOpen(); } public void setMinimize(byte minimize) { this.minimize = minimize; } public void startDocument() throws SAXException { if (!omitXmlDeclaration && false) { write(""); write(lineSeparator); } } public void characters(char cbuf[], int off, int len) throws SAXException { if (len == 0) return; if (inStartTag) finishStartTag(); do { char c = cbuf[off++]; switch (c) { case '\n': write(lineSeparator); break; case '&': write("&"); break; case '<': write("<"); break; case '>': write(">"); break; default: if (c < 0x80) write(c); else { write(c); } } } while (--len > 0); } public void rawCharacters(String chars) throws SAXException { if (inStartTag) finishStartTag(); write(chars); } public void ignorableWhitespace (char ch[], int start, int length) throws SAXException { for (; length > 0; length--, start++) write(ch[start]); } public void startElement(String name, AttributeList atts) throws SAXException { if (inStartTag) finishStartTag(); if (isStructElement(name, atts)) { writeStartStructElement(name, atts); } else { if (outputDoctype) { outputDoctype = false; write("= 0 ?'\'' : '"'; write(lit); write(doctypePublic); write(lit); } else write(" SYSTEM"); if (doctypeSystem != null) { char lit = doctypePublic.indexOf('"') >= 0 ?'\'' : '"'; write(' '); write(lit); write(doctypeSystem); write(lit); } write('>'); write(lineSeparator); } write('<'); write(name); int n = atts.getLength(); for (int i = 0; i < n; i++) { write(' '); write(atts.getName(i)); write('='); write('"'); attributeValue(atts.getValue(i)); write('"'); } inStartTag = true; } } boolean isStructElement(String name, AttributeList atts) throws SAXException { if (structNsPrefix == null) { int n = atts.getLength(); for (int i = 0; i < n; i++) { if (atts.getValue(i).equals("http://4xt.org/ns/xmlstructure")) { String aname=atts.getName(i); if (aname.startsWith("xmlns:")) { structNsPrefix = aname.substring(6)+":"; structNsPrefixSize = structNsPrefix.length(); break; } } } } return isStructElement(name); } boolean isStructElement(String name) throws SAXException { return ((structNsPrefix != null) && (name.startsWith(structNsPrefix))); } void writeStartStructElement(String name, AttributeList atts) throws SAXException { name = name.substring(structNsPrefixSize); if (name.equals("X-M-L-Decl")) writeXMLDeclaration(atts); else if (name.equals("doctype")) writeStartDoctype(atts); else if (name.equals("externalEntityDefinition")) writeExternalEntityDefinition(atts); else if (name.equals("comment")) writeStartComment(atts); else if (name.equals("entity")) writeEntity(atts); } void writeEndStructElement(String name) throws SAXException { name = name.substring(structNsPrefixSize); if (name.equals("doctype")) writeEndDoctype(); else if (name.equals("comment")) writeEndComment(); } void writeXMLDeclaration(AttributeList atts) throws SAXException { String version=null; encoding=null; String standalone=null; int n = atts.getLength(); for (int i = 0; i < n; i++) { String aname=atts.getName(i); if ((aname.substring(structNsPrefixSize)).equals("encoding")) encoding=atts.getValue(i); else if ((aname.substring(structNsPrefixSize)).equals("version")) version=atts.getValue(i); else if ((aname.substring(structNsPrefixSize)).equals("standalone")) standalone=atts.getValue(i); } try { initWriter(); } catch (IOException e) { // should be handled... } write ("\n"); } void writeStartDoctype(AttributeList atts) throws SAXException { String name=null; String publicId=null; String systemId=null; int n = atts.getLength(); for (int i = 0; i < n; i++) { String aname=atts.getName(i); if ((aname.substring(structNsPrefixSize)).equals("name")) name=atts.getValue(i); else if ((aname.substring(structNsPrefixSize)).equals("publicId")) publicId=atts.getValue(i); else if ((aname.substring(structNsPrefixSize)).equals("systemId")) systemId=atts.getValue(i); } write ("\n"); } void writeExternalEntityDefinition(AttributeList atts) throws SAXException { String name=null; String systemId=null; int n = atts.getLength(); for (int i = 0; i < n; i++) { String aname=atts.getName(i); if ((aname.substring(structNsPrefixSize)).equals("name")) name=atts.getValue(i); else if ((aname.substring(structNsPrefixSize)).equals("systemId")) systemId=atts.getValue(i); } write ("\n"); } void writeEntity(AttributeList atts) throws SAXException { String name=null; int n = atts.getLength(); for (int i = 0; i < n; i++) { String aname=atts.getName(i); if ((aname.substring(structNsPrefixSize)).equals("name")) name=atts.getValue(i); break; } write ("&"+ name+";"); } void writeStartComment(AttributeList atts) throws SAXException { write ("\n"); } protected void attributeValue(String value) throws SAXException { int valueLength = value.length(); for (int j = 0; j < valueLength; j++) { char c = value.charAt(j); switch (c) { case '\n': write(" "); break; case '&': write("&"); break; case '<': write("<"); break; case '"': write("""); break; case '\r': write(" "); break; case '\t': write(" "); break; default: if (c < 0x80) write(c); else { write(c); } break; } } } private final void finishStartTag() throws SAXException { inStartTag = false; write('>'); } public void processingInstruction(String target, String data) throws SAXException { if (target == null) { comment(data); return; } if (inStartTag) finishStartTag(); write('<'); write('?'); write(target); if (data.length() > 0) { write(' '); writeMarkup(data); } write('?'); write('>'); } public void markup(String chars) throws SAXException { if (inStartTag) finishStartTag(); writeMarkup(chars); } public void comment(String body) throws SAXException { if (inStartTag) finishStartTag(); write(""); } private void writeMarkup(String str) throws SAXException { int len = str.length(); for (int i = 0; i < len; i++) { char c = str.charAt(i); if (c == '\n') write(lineSeparator); else if (c < 0x80) write(c); else { write(c); } } } private final void flushBuf() throws SAXException { try { writer.write(buf, 0, bufUsed); } catch (IOException e) { throw new SAXException(e); } bufUsed = 0; } public void setDocumentLocator(Locator loc) { } public void endDocument() throws SAXException { write(lineSeparator); if (bufUsed != 0) flushBuf(); try { if (keepOpen) writer.flush(); else writer.close(); } catch (IOException e) { throw new SAXException(e); } writer = null; buf = null; } private final void write(String s) throws SAXException { int start = 0; int len = s.length(); int avail = buf.length - bufUsed; while (avail < len) { s.getChars(start, start + avail, buf, bufUsed); bufUsed = buf.length; flushBuf(); start += avail; len -= avail; avail = buf.length; } s.getChars(start, start + len, buf, bufUsed); bufUsed += len; } private final void write(char b) throws SAXException { if (bufUsed == buf.length) flushBuf(); buf[bufUsed++] = b; } public void endElement(String name) throws SAXException { if (isStructElement(name)) { writeEndStructElement(name); } else { if (inStartTag) { inStartTag = false; if (minimize != MINIMIZE_NONE) { if (minimize == MINIMIZE_EMPTY_ELEMENTS_HTML) write(' '); write('/'); write('>'); return; } write('>'); } write('<'); write('/'); write(name); write('>'); } } }