DomPrintUtil.java Source code

Java tutorial

Introduction

Here is the source code for DomPrintUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2008 IBM Corporation and Others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Kentarou FUKUDA - initial API and implementation
 *******************************************************************************/

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.html.HTMLTitleElement;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;

/**
 * Utility class to print out DOM
 */
@SuppressWarnings("nls")
public class DomPrintUtil {

    /**
     * Default encoding of this utility. (UTF8)
     */
    public static final String UTF8 = "UTF8";

    private static final String LINE_SEP = System.getProperty("line.separator");
    private static final String EMPTY_STR = "";

    private static final String LT = "<";
    private static final String GT = ">";
    private static final String AMP = "&";
    private static final String QUAT = "\"";
    private static final String SINGLE_QUAT = "'";

    private static final String ESC_LT = "&lt;";
    private static final String ESC_GT = "&gt;";
    private static final String ESC_AMP = "&amp;";

    private Document document;
    private int whatToShow = NodeFilter.SHOW_ALL;
    private NodeFilter nodeFilter = null;
    private boolean entityReferenceExpansion = false;

    private boolean indent = true;
    private boolean escapeTagBracket = false;

    private AttributeFilter attrFilter = null;

    /**
     * AttributeFilter defines the behavior of a filter that is used for
     * converting attributes of each Element into String.
     */
    public interface AttributeFilter {

        /**
         * Check whether a specified attribute is converted into String.
         * 
         * @param element
         *            the target Element
         * @param attr
         *            the target attribute
         * @return true to print the attribute, false to ignore the attribute
         */
        public boolean acceptNode(Element element, Node attr);
    }

    /**
     * Constructor of DOM print utility.
     * 
     * @param document
     *            the target document
     */
    public DomPrintUtil(Document document) {
        this.document = document;
    }

    private String getXMLString(String targetS) {
        return targetS.replaceAll(AMP, ESC_AMP).replaceAll(LT, ESC_LT).replaceAll(GT, ESC_GT);
    }

    private String getAttributeString(Element element, Node attr) {
        if (null == attrFilter || attrFilter.acceptNode(element, attr)) {
            String value = getXMLString(attr.getNodeValue());
            String quat = QUAT;
            if (value.indexOf(QUAT) > 0) {
                quat = SINGLE_QUAT;
            }
            return " " + attr.getNodeName() + "=" + quat + value + quat;
        }
        return EMPTY_STR;
    }

    private boolean checkNewLine(Node target) {
        if (indent && target.hasChildNodes()) {
            short type = target.getFirstChild().getNodeType();
            if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
                return false;
            }
            return true;
        }
        return false;
    }

    /**
     * Returns XML text converted from the target DOM
     * 
     * @return String format XML converted from the target DOM
     */
    public String toXMLString() {
        StringBuffer tmpSB = new StringBuffer(8192);

        TreeWalkerImpl treeWalker = new TreeWalkerImpl(document, whatToShow, nodeFilter, entityReferenceExpansion);

        String lt = escapeTagBracket ? ESC_LT : LT;
        String gt = escapeTagBracket ? ESC_GT : GT;
        String line_sep = indent ? LINE_SEP : EMPTY_STR;

        Node tmpN = treeWalker.nextNode();
        boolean prevIsText = false;

        String indentS = EMPTY_STR;
        while (tmpN != null) {
            short type = tmpN.getNodeType();
            switch (type) {
            case Node.ELEMENT_NODE:
                if (prevIsText) {
                    tmpSB.append(line_sep);
                }
                tmpSB.append(indentS + lt + tmpN.getNodeName());
                NamedNodeMap attrs = tmpN.getAttributes();
                int len = attrs.getLength();
                for (int i = 0; i < len; i++) {
                    Node attr = attrs.item(i);
                    String value = attr.getNodeValue();
                    if (null != value) {
                        tmpSB.append(getAttributeString((Element) tmpN, attr));
                    }
                }
                if (tmpN instanceof HTMLTitleElement && !tmpN.hasChildNodes()) {
                    tmpSB.append(gt + ((HTMLTitleElement) tmpN).getText());
                    prevIsText = true;
                } else if (checkNewLine(tmpN)) {
                    tmpSB.append(gt + line_sep);
                    prevIsText = false;
                } else {
                    tmpSB.append(gt);
                    prevIsText = true;
                }
                break;
            case Node.TEXT_NODE:
                if (!prevIsText) {
                    tmpSB.append(indentS);
                }
                tmpSB.append(getXMLString(tmpN.getNodeValue()));
                prevIsText = true;
                break;
            case Node.COMMENT_NODE:
                String comment;
                if (escapeTagBracket) {
                    comment = getXMLString(tmpN.getNodeValue());
                } else {
                    comment = tmpN.getNodeValue();
                }
                tmpSB.append(line_sep + indentS + lt + "!--" + comment + "--" + gt + line_sep);
                prevIsText = false;
                break;
            case Node.CDATA_SECTION_NODE:
                tmpSB.append(line_sep + indentS + lt + "!CDATA[" + tmpN.getNodeValue() + "]]" + line_sep);
                break;
            case Node.DOCUMENT_TYPE_NODE:
                if (tmpN instanceof DocumentType) {
                    DocumentType docType = (DocumentType) tmpN;
                    String pubId = docType.getPublicId();
                    String sysId = docType.getSystemId();
                    if (null != pubId && pubId.length() > 0) {
                        if (null != sysId && sysId.length() > 0) {
                            tmpSB.append(lt + "!DOCTYPE " + docType.getName() + " PUBLIC \"" + pubId + " \"" + sysId
                                    + "\">" + line_sep);
                        } else {
                            tmpSB.append(
                                    lt + "!DOCTYPE " + docType.getName() + " PUBLIC \"" + pubId + "\">" + line_sep);
                        }
                    } else {
                        tmpSB.append(lt + "!DOCTYPE " + docType.getName() + " SYSTEM \"" + docType.getSystemId()
                                + "\">" + line_sep);

                    }
                } else {
                    System.out.println("Document Type node does not implement DocumentType: " + tmpN);
                }
                break;
            default:
                System.out.println(tmpN.getNodeType() + " : " + tmpN.getNodeName());
            }

            Node next = treeWalker.firstChild();
            if (null != next) {
                if (indent && type == Node.ELEMENT_NODE) {
                    indentS = indentS + " ";
                }
                tmpN = next;
                continue;
            }

            if (tmpN.getNodeType() == Node.ELEMENT_NODE) {
                tmpSB.append(lt + "/" + tmpN.getNodeName() + gt + line_sep);
                prevIsText = false;
            }

            next = treeWalker.nextSibling();
            if (null != next) {
                tmpN = next;
                continue;
            }

            tmpN = null;
            next = treeWalker.parentNode();
            while (null != next) {
                if (next.getNodeType() == Node.ELEMENT_NODE) {
                    if (indent) {
                        if (indentS.length() > 0) {
                            indentS = indentS.substring(1);
                        } else {
                            System.err.println("indent: " + next.getNodeName() + " " + next);
                        }
                    }
                    tmpSB.append(line_sep + indentS + lt + "/" + next.getNodeName() + gt + line_sep);
                    prevIsText = false;
                }
                next = treeWalker.nextSibling();
                if (null != next) {
                    tmpN = next;
                    break;
                }
                next = treeWalker.parentNode();
            }
        }
        return tmpSB.toString();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return toXMLString();
    }

    /**
     * Set whatToShow attribute to TreeWalker used in the utility.
     * 
     * @param whatToShow
     *            the attribute determines which types of node are presented via
     *            the TreeWalker. The values are defined in the NodeFilter
     *            interface.
     * @see TreeWalkerImpl
     */
    public void setWhatToShow(int whatToShow) {
        this.whatToShow = whatToShow;
    }

    /**
     * Set NodeFilter to TreeWalker used in the utility.
     * 
     * @param nodeFilter
     *            the filter used to screen nodes
     * @see TreeWalkerImpl
     */
    public void setNodeFilter(NodeFilter nodeFilter) {
        this.nodeFilter = nodeFilter;
    }

    /**
     * Set the entity reference expansion flag to TreeWalker used in the
     * utility.
     * 
     * @param entityReferenceExpansion
     *            the flag to determine whether the children of entity reference
     *            nodes are visible to TreeWalker.
     * @see TreeWalkerImpl
     */
    public void setEntityReferenceExpansion(boolean entityReferenceExpansion) {
        this.entityReferenceExpansion = entityReferenceExpansion;
    }

    /**
     * Set the number of space characters used for indent
     * 
     * @param indent
     *            the number of space characters used for indent
     */
    public void setIndent(boolean indent) {
        this.indent = indent;
    }

    /**
     * Determine to escape Tag bracket ('<','>') or not. Please set true if you
     * want to print out DOM into &lt;pre&gt; section of HTML.
     * 
     * @param escapeTagBracket
     *            if true, print Tag bracket as escaped format ({@literal '&lt;',
     *            '&gt;'})
     * 
     */
    public void setEscapeTagBracket(boolean escapeTagBracket) {
        this.escapeTagBracket = escapeTagBracket;
    }

    /**
     * Set AttributeFilter to define the behavior for printing attributes of
     * each Element.
     * 
     * @param attrFilter
     *            the AttributeFilter to set
     */
    public void setAttrFilter(AttributeFilter attrFilter) {
        this.attrFilter = attrFilter;
    }

    /**
     * Print out the target Document.
     * 
     * @param filePath
     *            the target file path
     * @throws IOException
     */
    public void writeToFile(String filePath) throws IOException {
        writeToFile(new File(filePath), UTF8);
    }

    /**
     * Print out the target Document.
     * 
     * @param file
     *            the target File
     * @throws IOException
     */
    public void writeToFile(File file) throws IOException {
        writeToFile(file, UTF8);
    }

    /**
     * Print out the target Document in specified encoding
     * 
     * @param filePath
     *            the target file path
     * @param encode
     *            the target encoding
     * @throws IOException
     */
    public void writeToFile(String filePath, String encode) throws IOException {
        writeToFile(new File(filePath), encode);
    }

    /**
     * Print out the target Document in specified encoding
     * 
     * @param file
     *            the target file
     * @param encode
     *            the target encoding
     * @throws IOException
     */
    public void writeToFile(File file, String encode) throws IOException {
        PrintWriter tmpPW = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), encode));
        tmpPW.println(toXMLString());
        tmpPW.flush();
        tmpPW.close();
    }

}

/*******************************************************************************
 * Copyright (c) 2008 IBM Corporation and Others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Kentarou FUKUDA - initial API and implementation
 *******************************************************************************/

class TreeWalkerImpl implements TreeWalker {

    private Node walkerRoot;
    private Node current;
    private int whatToShow;
    private NodeFilter filter;
    private NodeFilter defaultFilter;
    private boolean entitiyReferenceExpansion;
    private boolean noFilter = true;

    public TreeWalkerImpl(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion)
            throws DOMException {
        if (null == root) {
            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Root can't be a null.");
        }
        this.walkerRoot = root;
        this.current = root;
        this.whatToShow = whatToShow;
        this.filter = filter;
        this.noFilter = (null == filter);
        this.entitiyReferenceExpansion = entityReferenceExpansion;
        this.defaultFilter = new WhatToShowNodeFilter(whatToShow);
    }

    private short eval(Node target) {
        short flag = defaultFilter.acceptNode(target);

        // If the node is skipped by whatToShow flag, a NodeFiilter will not be
        // called.
        if (noFilter || flag == NodeFilter.FILTER_SKIP) {
            return flag;
        }
        return filter.acceptNode(target);
    }

    private Node getVisibleNextSibling(Node target, Node root) {
        if (target == root) {
            return null;
        }
        Node tmpN = target.getNextSibling();
        if (null == tmpN) {
            Node tmpP = target.getParentNode();
            if (eval(tmpP) == NodeFilter.FILTER_SKIP) {
                return getVisibleNextSibling(tmpP, root);
            }
            return null;
        }
        switch (eval(tmpN)) {
        case NodeFilter.FILTER_ACCEPT:
            return tmpN;
        case NodeFilter.FILTER_SKIP:
            Node tmpC = getVisibleFirstChild(tmpN);
            if (null != tmpC) {
                return tmpC;
            }
            // case NodeFilter.FILTER_REJECT:
        default:
            return getVisibleNextSibling(tmpN, root);
        }
    }

    private Node getVisiblePreviousSibling(Node target, Node root) {
        if (target == root) {
            return null;
        }
        Node tmpN = target.getPreviousSibling();
        if (null == tmpN) {
            Node tmpP = target.getParentNode();
            if (eval(tmpP) == NodeFilter.FILTER_SKIP) {
                return getVisiblePreviousSibling(tmpP, root);
            }
            return null;
        }
        switch (eval(tmpN)) {
        case NodeFilter.FILTER_ACCEPT:
            return tmpN;
        case NodeFilter.FILTER_SKIP:
            Node tmpC = getVisibleLastChild(tmpN);
            if (null != tmpC) {
                return tmpC;
            }
            // case NodeFilter.FILTER_REJECT:
        default:
            return getVisiblePreviousSibling(tmpN, root);
        }
    }

    private Node getVisibleFirstChild(Node target) {
        if (!entitiyReferenceExpansion && Node.ENTITY_REFERENCE_NODE == target.getNodeType()) {
            return null;
        }
        Node tmpN = target.getFirstChild();
        if (null == tmpN) {
            return null;
        }

        switch (eval(tmpN)) {
        case NodeFilter.FILTER_ACCEPT:
            return tmpN;
        case NodeFilter.FILTER_SKIP:
            Node tmpN2 = getVisibleFirstChild(tmpN);
            if (null != tmpN2) {
                return tmpN2;
            }
            // case NodeFilter.FILTER_REJECT:
        default:
            return getVisibleNextSibling(tmpN, target);
        }
    }

    private Node getVisibleLastChild(Node target) {
        if (!entitiyReferenceExpansion && Node.ENTITY_REFERENCE_NODE == target.getNodeType()) {
            return null;
        }
        Node tmpN = target.getLastChild();
        if (null == tmpN) {
            return null;
        }

        switch (eval(tmpN)) {
        case NodeFilter.FILTER_ACCEPT:
            return tmpN;
        case NodeFilter.FILTER_SKIP:
            Node tmpN2 = getVisibleLastChild(tmpN);
            if (null != tmpN2) {
                return tmpN2;
            }
            // case NodeFilter.FILTER_REJECT:
        default:
            return getVisiblePreviousSibling(tmpN, target);
        }
    }

    private Node getVisibleParent(Node target) {
        if (target == walkerRoot) {
            return null;
        }
        Node tmpN = target.getParentNode();
        if (null == tmpN) {
            return null;
        }
        switch (eval(tmpN)) {
        case NodeFilter.FILTER_ACCEPT:
            return tmpN;
        // case NodeFilter.FILTER_SKIP:
        // case NodeFilter.FILTER_REJECT:
        default:
            return getVisibleParent(tmpN);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#firstChild()
     */
    public Node firstChild() {
        Node result = getVisibleFirstChild(current);
        if (null != result) {
            current = result;
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#getCurrentNode()
     */
    public Node getCurrentNode() {
        return current;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#getExpandEntityReferences()
     */
    public boolean getExpandEntityReferences() {
        return entitiyReferenceExpansion;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#getFilter()
     */
    public NodeFilter getFilter() {
        return filter;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#getRoot()
     */
    public Node getRoot() {
        return walkerRoot;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#getWhatToShow()
     */
    public int getWhatToShow() {
        return whatToShow;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#lastChild()
     */
    public Node lastChild() {
        Node result = getVisibleLastChild(current);
        if (null != result) {
            current = result;
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#nextNode()
     */
    public Node nextNode() {
        // search child
        Node tmpN = getVisibleFirstChild(current);
        if (null != tmpN) {
            current = tmpN;
            return tmpN;
        }

        // search sibling
        tmpN = getVisibleNextSibling(current, walkerRoot);
        if (null != tmpN) {
            current = tmpN;
            return tmpN;
        }

        // search parent's sibling
        Node tmpP = getVisibleParent(current);
        while (null != tmpP) {
            tmpN = getVisibleNextSibling(tmpP, walkerRoot);
            if (null != tmpN) {
                current = tmpN;
                return tmpN;
            } else {
                tmpP = getVisibleParent(tmpP);
            }
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#nextSibling()
     */
    public Node nextSibling() {
        Node result = getVisibleNextSibling(current, walkerRoot);
        if (null != result) {
            current = result;
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#parentNode()
     */
    public Node parentNode() {
        Node result = getVisibleParent(current);
        if (null != result) {
            current = result;
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#previousNode()
     */
    public Node previousNode() {
        // search previous sibling
        Node tmpN = getVisiblePreviousSibling(current, walkerRoot);
        // no sibling, search parent
        if (null == tmpN) {
            tmpN = getVisibleParent(current);
            if (null != tmpN) {
                current = tmpN;
                return tmpN;
            }
            return null;
        }

        // search last child of previous sibling
        Node tmpC = getVisibleLastChild(tmpN);
        while (null != tmpC) {
            tmpN = tmpC;
            tmpC = getVisibleLastChild(tmpN);
        }
        if (null != tmpN) {
            current = tmpN;
            return tmpN;
        }

        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#previousSibling()
     */
    public Node previousSibling() {
        Node result = getVisiblePreviousSibling(current, walkerRoot);
        if (null != result) {
            current = result;
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.TreeWalker#setCurrentNode(org.w3c.dom.Node)
     */
    public void setCurrentNode(Node arg0) {
        if (arg0 == null) {
            System.out.println("Current node can't be null.");
        }
        current = arg0;
    }

}

/*******************************************************************************
 * Copyright (c) 2008 IBM Corporation and Others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Kentarou FUKUDA - initial API and implementation
 *******************************************************************************/
class WhatToShowNodeFilter implements NodeFilter {

    private int filter;

    public WhatToShowNodeFilter(int whatToShow) {
        this.filter = whatToShow;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.w3c.dom.traversal.NodeFilter#acceptNode(org.w3c.dom.Node)
     */
    public short acceptNode(Node arg0) {
        if (null == arg0) {
            return FILTER_REJECT;
        }

        if ((filter & (1 << (arg0.getNodeType() - 1))) != 0) {
            return FILTER_ACCEPT;
        }
        return FILTER_SKIP;
    }
}