| 
/** Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
 package com.opensymphony.provider.xmlprinter;
 
 import com.opensymphony.provider.ProviderConfigurationException;
 import com.opensymphony.provider.XMLPrinterProvider;
 
 import org.w3c.dom.*;
 
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
 
 
 /**
 * XMLPrinterProvider implementation with no dependencies to other printers.
 * Uses very simple recursive walk down tree writing as it goes. Lacks
 * many features (including support for namespaces), normalization,
 * and flexible formatting options, but it's fast, very small and standalone.
 *
 * @author <a href="mailto:[email protected]">Joe Walnes</a>
 * @version $Revision: 5 $
 */
 public class DefaultXMLPrinterProvider implements XMLPrinterProvider {
 //~ Static fields/initializers /////////////////////////////////////////////
 
 private static final String INDENT = "  ";
 
 //~ Methods ////////////////////////////////////////////////////////////////
 
 public void destroy() {
 }
 
 public void init() throws ProviderConfigurationException {
 }
 
 public void print(Document doc, Writer out) throws IOException {
 PrintWriter printWriter = new PrintWriter(out);
 walk(printWriter, doc, 0, false);
 printWriter.flush();
 out.flush();
 }
 
 /**
 * Escape text and strip line breaks.
 */
 private void escape(PrintWriter out, String str) throws IOException {
 if (str == null) {
 return;
 }
 
 str = str.trim();
 
 for (int i = 0; i < str.length(); i++) {
 char c = str.charAt(i);
 
 switch (c) {
 case '<':
 out.print("<");
 
 break;
 
 case '>':
 out.print(">");
 
 break;
 
 case '&':
 out.print("&");
 
 break;
 
 case '"':
 out.print(""");
 
 break;
 
 case '\r':
 case '\n':
 break;
 
 default:
 out.print(c);
 }
 }
 }
 
 /**
 * Add indentation.
 */
 private void indent(PrintWriter out, int level) throws IOException {
 for (int i = 0; i < level; i++) {
 out.print(INDENT);
 }
 }
 
 private void walk(PrintWriter out, Node node, int indent, boolean textOnly) throws IOException {
 if (node == null) {
 return;
 }
 
 int type = node.getNodeType();
 
 boolean keepFormatting = (textOnly && (type == Node.TEXT_NODE)) || (type == Node.CDATA_SECTION_NODE);
 
 if (!keepFormatting) {
 indent(out, indent);
 }
 
 switch (type) {
 // Top of document
 case Node.DOCUMENT_NODE:
 out.print("<?xml version=\"1.0\" ?>\n");
 walk(out, ((Document) node).getDocumentElement(), indent, false);
 
 break;
 
 // Element (tag)
 case Node.ELEMENT_NODE:
 
 // open tag
 out.print('<');
 out.print(node.getNodeName());
 
 // add attributes
 NamedNodeMap attrs = node.getAttributes();
 
 for (int i = 0; i < attrs.getLength(); i++) {
 Node attr = attrs.item(i);
 out.print(' ');
 out.print(attr.getNodeName());
 out.print("=\"");
 escape(out, attr.getNodeValue());
 out.print('"');
 }
 
 NodeList children = node.getChildNodes();
 
 // empty tag if no children
 if ((children == null) || (children.getLength() == 0)) {
 out.print('/');
 }
 
 out.print('>');
 
 // walk children
 if (children != null) {
 boolean nodeTextOnly = false;
 
 if ((children.getLength() == 1) && (children.item(0).getNodeType() == Node.TEXT_NODE)) {
 nodeTextOnly = true;
 }
 
 if ((children.getLength() > 0) && !nodeTextOnly) {
 out.print('\n');
 }
 
 for (int i = 0; i < children.getLength(); i++) {
 walk(out, children.item(i), indent + 1, nodeTextOnly);
 }
 
 if ((children.getLength() > 0) && !nodeTextOnly) {
 indent(out, indent);
 }
 }
 
 // close tag
 if (children.getLength() > 0) {
 out.print("</");
 out.print(node.getNodeName());
 out.print('>');
 }
 
 break;
 
 // text or cdata
 case Node.CDATA_SECTION_NODE:
 case Node.TEXT_NODE:
 escape(out, node.getNodeValue());
 
 break;
 
 // processing instruction
 case Node.PROCESSING_INSTRUCTION_NODE:
 out.print("<?");
 out.print(node.getNodeName());
 
 if ((node.getNodeValue() != null) && (node.getNodeValue().length() > 0)) {
 out.print(' ');
 out.print(node.getNodeValue());
 }
 
 out.print("?>");
 
 break;
 
 // entity reference ( &blah; )
 case Node.ENTITY_REFERENCE_NODE:
 out.print('&');
 out.print(node.getNodeName());
 out.print(';');
 
 break;
 }
 
 if (!keepFormatting) {
 out.print('\n');
 }
 }
 }
 |