Java tutorial
/******************************************************************************* * 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 = "<"; private static final String ESC_GT = ">"; private static final String ESC_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 <pre> section of HTML. * * @param escapeTagBracket * if true, print Tag bracket as escaped format ({@literal '<', * '>'}) * */ 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; } }