This page was generated using Webiyo. See its source code and unit tests.
|
org/webiyo/xml/XmlWriter.javapackage org.webiyo.xml; import org.w3c.dom.*; import java.io.Closeable; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class XmlWriter implements Closeable { private Appendable out; private boolean atStartOfLine = true; private final List<TagType> tagStack = new ArrayList<TagType>(); private final AttributeSink atttributeSink; public XmlWriter(Appendable appendable) { out = appendable; atttributeSink = new AttributeSink() { public void putAttribute(String name, String value) throws IOException { appendAttribute(name, value); } }; } public XmlWriter(File outputFile) throws IOException { this(new FileWriter(outputFile)); } public void declareEntities(TagType rootTag, CharEntity... entities) throws IOException { out.append("<?xml version=\"1.0\"?>"); println(); out.append("<!DOCTYPE " + rootTag.getName() + " [\n"); for (CharEntity entity : entities) { out.append(" "); out.append(entity.getDeclaration()); out.append("\n"); } out.append("]>"); println(); } public void startPage(DocType docType) throws IOException { TagType rootTag = docType.getRootTag(); out.append("<?xml version=\"1.0\"?>"); println(); out.append("<!DOCTYPE " + rootTag.getName() + " PUBLIC \""); out.append(docType.getPublicId()); out.append("\" \""); out.append(docType.getUrl()); out.append("\">"); println(); startTag(rootTag); } public void startTag(TagType newTag, AttributeSource... atts) throws IOException { checkCanStartTag(newTag); tagStack.add(newTag); openStartTag(newTag.getName(), newTag.isOnSeparateLine()); for (AttributeSource att : atts) { att.sendAttributes(atttributeSink); } out.append('>'); atStartOfLine = false; } public void endTag(TagType tagToEnd) throws IOException { String tagName = tagToEnd.getName(); if (tagStack.size() == 0) { throw new XmlOutputException("</" + tagName + "> doesn't match anything"); } if (top() != tagToEnd) { throw new XmlOutputException("<" + top().getName() + "> and </" + tagName + "> don't match"); } tagStack.remove(tagStack.size() - 1); endTag(tagName); if (tagToEnd.isOnSeparateLine()) { println(); } } public void tag(TagType tagType, AttributeSource... atts) throws IOException { checkCanStartTag(tagType); openStartTag(tagType.getName(), tagType.isOnSeparateLine()); for (AttributeSource att : atts) { att.sendAttributes(atttributeSink); } out.append("/>"); if (tagType.isOnSeparateLine()) println(); } public void text(String text) throws IOException { appendEscaped(text, false); } public void text(TagType tagType, String text) throws IOException { startTag(tagType); text(text); endTag(tagType); } public void entity(String name) throws IOException { out.append("&"); out.append(name); out.append(";"); } public void renderElement(Element element) throws IOException { openStartTag(element.getNodeName(), true); NamedNodeMap atts = element.getAttributes(); for (int i = 0; i < atts.getLength(); i++) { Attr att = (Attr) atts.item(i); appendAttribute(att.getName(), att.getValue()); } out.append('>'); atStartOfLine = false; NodeList children = element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child instanceof Element) { renderElement((Element) child); } else if (child instanceof Text) { Text text = (Text) child; text(text.getWholeText()); } else { throw new XmlOutputException("unknown node: " + child); } } endTag(element.getNodeName()); } public void endPage() throws IOException { if (tagStack.size() != 1) { throw new XmlOutputException("endPage() doesn't match declareEntities()"); } endTag(top()); } public void close() throws IOException { if (out instanceof Closeable) { Closeable closable = (Closeable) out; out = null; closable.close(); } else { out = null; } } // end of public methods private void endTag(String tagName) throws IOException { out.append("</"); out.append(tagName); out.append('>'); } private void appendEscaped(String text, boolean escapeQuotes) throws IOException { char[] chars = text.toCharArray(); for (char c : chars) { switch (c) { case '<': out.append("<"); break; case '>': out.append(">"); break; case '&': out.append("&"); break; case '"': if (escapeQuotes) { out.append("""); } else { out.append(c); } break; default: out.append(c); } } atStartOfLine = false; } private void appendAttribute(String attName, Object attValue) throws IOException { out.append(' '); out.append(attName); out.append('=').append('"'); appendEscaped(attValue.toString(), true); out.append('"'); } private void openStartTag(String tagName, boolean separateLine) throws IOException { if (!atStartOfLine && separateLine) println(); out.append('<'); out.append(tagName); } private void checkCanStartTag(TagType newTag) throws XmlOutputException { if (tagStack.size() > 0) { if (!top().allows(newTag)) { throw new XmlOutputException("<" + top().getName() + "> doesn't allow <" + newTag.getName() + ">"); } } } private TagType top() { return tagStack.get(tagStack.size() - 1); } private void println() throws IOException { out.append('\n'); atStartOfLine = true; } } |