package org.madore.damlengine; import java.io.Writer; import java.io.IOException; import org.w3c.dom.*; public final class Unparser { private final Document doc; private Node cursor; private enum Dir { PUSHING, POPPING } private Dir dir; private final Writer out; private final String forceDoctype; public Unparser(Document doc, Writer out, String forceDoctype) { this.doc = doc; this.out = out; this.forceDoctype = forceDoctype; } protected void enter() { Node chld = cursor.getFirstChild(); if ( chld == null ) { dir = Dir.POPPING; } else { cursor = chld; dir = Dir.PUSHING; } } protected void skip() { Node nsib = cursor.getNextSibling(); if ( nsib == null ) { cursor = cursor.getParentNode(); dir = Dir.POPPING; } else { cursor = nsib; dir = Dir.PUSHING; } } public static String quote(String s) { StringBuilder buf = new StringBuilder(s.length()+64); int ptr0 = 0; int ptr; for ( ptr=0 ; ptr': qch = ">"; break; case '"': qch = """; break; } if ( qch != null ) { buf.append(s, ptr0, ptr); buf.append(qch); ptr0 = ptr+1; } } buf.append(s, ptr0, ptr); return buf.toString(); } protected void unparseOne() throws IOException { // System.err.println("unparseOne(): cursor.nodeName="+cursor.getNodeName()); switch ( dir ) { case PUSHING: if ( cursor.getNodeType() == Node.ELEMENT_NODE ) { Element elt = (Element)cursor; String qname = elt.getTagName(); out.write("<"+qname); if ( elt.hasAttributes() ) { NamedNodeMap attrs = elt.getAttributes(); Node n2; for ( int i=0 ; (n2=attrs.item(i)) != null ; i++ ) { Attr attr = (Attr)n2; String aname = attr.getName(); out.write(" "+aname+"=\""+quote(attr.getValue())+"\""); if ( aname.equals("xml:lang") && elt.getNamespaceURI().equals(DamlEngine.XHTML_NS) ) out.write(" lang=\""+quote(attr.getValue())+"\""); } } if ( ! elt.hasChildNodes() && ( qname.equals("br") || qname.equals("hr") || qname.equals("img") || qname.equals("area") || qname.equals("base") || qname.equals("basefont") || qname.equals("col") || qname.equals("frame") || qname.equals("input") || qname.equals("isindex") || qname.equals("link") || qname.equals("meta") || qname.equals("param") ) ) { out.write(" />"); skip(); } else { out.write(">"); enter(); } } else if ( cursor.getNodeType() == Node.DOCUMENT_NODE ) { enter(); } else if ( cursor.getNodeType() == Node.TEXT_NODE ) { out.write(quote(((Text)cursor).getData())); skip(); } else if ( cursor.getNodeType() == Node.COMMENT_NODE ) { // FIXME: comments could conceivably contain the "--" string out.write(""); skip(); } else if ( cursor.getNodeType() == Node.CDATA_SECTION_NODE ) { // FIXME: cdata section could conceivably contain the "]]>" string out.write(""); skip(); } else { skip(); } break; case POPPING: if ( cursor.getNodeType() == Node.ELEMENT_NODE ) { Element elt = (Element)cursor; out.write(""); } skip(); break; } } public void unparse() throws IOException { // out.write(""); if ( forceDoctype == null ) { DocumentType doctype = doc.getDoctype(); if ( doctype != null ) { String externalId = ""; if ( doctype.getPublicId() != null ) { externalId = " PUBLIC \""+doctype.getPublicId()+"\" \"" +doctype.getSystemId()+"\""; } else if ( doctype.getSystemId() != null ) { externalId = " SYSTEM \""+doctype.getSystemId()+"\""; } out.write("\n"); } else out.write("\n"); } else { out.write("\n"); } cursor = doc.getDocumentElement(); dir = Dir.PUSHING; while ( cursor != null ) { unparseOne(); } out.write("\n"); out.flush(); } }