/******************************************************************************* * Copyright (c) 2003, 2011 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: * IBM Corporation - Initial API and implementation *******************************************************************************/ package org.eclipse.jst.server.tomcat.core.internal.xml; import java.util.LinkedHashMap; import java.util.Map; import org.w3c.dom.*; /** * An XML element. */ public class XMLElement { private Element xmlElement; protected Factory factory; public XMLElement() { // do nothing } public Element getElementNode() { return xmlElement; } public Attr addAttribute(String s, String s1) { Attr attr = factory.createAttribute(s, xmlElement); attr.setValue(s1); return attr; } public XMLElement createElement(int index, String s) { return factory.createElement(index, s, xmlElement); } public XMLElement createElement(String s) { return factory.createElement(s, xmlElement); } public XMLElement findElement(String s) { NodeList nodelist = xmlElement.getElementsByTagName(s); int i = nodelist == null ? 0 : nodelist.getLength(); for (int j = 0; j < i; j++) { Node node = nodelist.item(j); String s1 = node.getNodeName().trim(); if (s1.equals(s)) return factory.newInstance((Element) node); } return createElement(s); } public XMLElement findElement(String s, int i) { NodeList nodelist = xmlElement.getElementsByTagName(s); int j = nodelist == null ? 0 : nodelist.getLength(); for (int k = 0; k < j; k++) { Node node = nodelist.item(k); String s1 = node.getNodeName().trim(); if (s1.equals(s) && k == i) return factory.newInstance((Element) node); } return createElement(s); } public String getAttributeValue(String s) { Attr attr = xmlElement.getAttributeNode(s); if (attr != null) return attr.getValue(); return null; } public Map getAttributes() { Map<String, String> attributes = new LinkedHashMap<String, String>(); NamedNodeMap attrs = xmlElement.getAttributes(); if (null != attrs) { for (int i = 0; i < attrs.getLength(); i++) { Node attr = attrs.item(i); String name = attr.getNodeName(); String value = attr.getNodeValue(); attributes.put(name, value); } } return attributes; } public String getElementName() { return xmlElement.getNodeName(); } public String getElementValue() { return getElementValue(xmlElement); } protected static String getElementValue(Element element) { String s = element.getNodeValue(); if (s != null) return s; NodeList nodelist = element.getChildNodes(); for (int i = 0; i < nodelist.getLength(); i++) if (nodelist.item(i) instanceof Text) return ((Text) nodelist.item(i)).getData(); return null; } public Element getSubElement(String s) { NodeList nodelist = xmlElement.getElementsByTagName(s); int i = nodelist == null ? 0 : nodelist.getLength(); for (int j = 0; j < i; j++) { Node node = nodelist.item(j); String s1 = node.getNodeName().trim(); if (s1.equals(s)) return (Element) node; } return null; } public String getSubElementValue(String s) { Element element = getSubElement(s); if (element == null) return null; String value = getElementValue(element); if (value == null) return null; return value.trim(); } public boolean removeAttribute(String s) { try { xmlElement.removeAttribute(s); return true; } catch (Exception ex) { return false; } } public boolean removeElement(String s, int i) { NodeList nodelist = xmlElement.getElementsByTagName(s); int j = nodelist == null ? 0 : nodelist.getLength(); for (int k = 0; k < j; k++) { Node node = nodelist.item(k); String s1 = node.getNodeName().trim(); if (s1.equals(s) && k == i) { xmlElement.removeChild(node); return true; } } return false; } public void setAttributeValue(String s, String s1) { Attr attr = xmlElement.getAttributeNode(s); if (attr == null) attr = addAttribute(s, s1); else attr.setValue(s1); } void setElement(Element element) { xmlElement = element; } protected static void setElementValue(Element element, String value) { String s = element.getNodeValue(); if (s != null) { element.setNodeValue(value); return; } NodeList nodelist = element.getChildNodes(); for (int i = 0; i < nodelist.getLength(); i++) if (nodelist.item(i) instanceof Text) { Text text = (Text) nodelist.item(i); text.setData(value); return; } return; } void setFactory(Factory factory1) { factory = factory1; } public void setSubElementValue(String s, String value) { Element element = getSubElement(s); if (element == null) { element = factory.document.createElement(s); element.appendChild(factory.document.createTextNode("temp")); xmlElement.appendChild(element); } setElementValue(element, value); } public int sizeOfElement(String s) { NodeList nodelist = xmlElement.getElementsByTagName(s); int i = nodelist == null ? 0 : nodelist.getLength(); return i; } public void updateElementValue(String s) { try { xmlElement.setNodeValue(s); } catch (DOMException ex) { NodeList nodelist = xmlElement.getChildNodes(); int i = nodelist == null ? 0 : nodelist.getLength(); if (i > 0) { for (int j = 0; j < i; j++) if (nodelist.item(j) instanceof Text) { ((Text) nodelist.item(j)).setData(s); return; } } else { xmlElement.appendChild(factory.document.createTextNode(s)); } } } public boolean hasChildNodes() { return xmlElement.hasChildNodes(); } public void removeChildren() { while (xmlElement.hasChildNodes()) { xmlElement.removeChild(xmlElement.getFirstChild()); } } public void copyChildrenTo(XMLElement destination) { NodeList nodelist = xmlElement.getChildNodes(); int len = nodelist == null ? 0 : nodelist.getLength(); for (int i = 0; i < len; i++) { Node node = nodelist.item(i); destination.importNode(node, true); } } public void importNode(Node node, boolean deep) { xmlElement.appendChild(xmlElement.getOwnerDocument().importNode(node, deep)); } /** * This method tries to compare two XMLElements for equivalence. Due to * the lack of normalization, they aren't compared for equality. Elements * are required to have the same attributes or the same node value * if attributes aren't present. Attributes and node value are assumed * to be mutually exclusive for Tomcat configuration XML files. The * same non-text child nodes are required to be present in an element * and appear in the same order. If a node type other than element or * comment is encountered, this method punts and returns false. * * @param obj XMLElement to compare * @return true if the elements are equivalent */ public boolean isEquivalent(XMLElement obj) { if (obj != null) { try { return elementsAreEquivalent(xmlElement, obj.getElementNode()); } catch (Exception e) { // Catch and ignore just to be safe } } return false; } /** * Same as isEquivalent() but doesn't ignore exceptions for test purposes. * This avoids hiding an expected mismatch behind an unexpected exception. * * @param obj XMLElement to compare * @return true if the elements are equivalent */ public boolean isEquivalentTest(XMLElement obj) { if (obj != null) { return elementsAreEquivalent(xmlElement, obj.getElementNode()); } return false; } private static boolean elementsAreEquivalent(Element element, Element otherElement) { if (element == otherElement) return true; if (!element.getNodeName().equals(otherElement.getNodeName())) return false; if (element.hasChildNodes()) { if (otherElement.hasChildNodes() && attributesAreEqual(element, otherElement)) { // Compare child nodes NodeList nodelist = element.getChildNodes(); NodeList otherNodelist = otherElement.getChildNodes(); if (nodelist.getLength() == otherNodelist.getLength()) { Node node = nextNonTextNode(element.getFirstChild()); Node otherNode = nextNonTextNode(otherElement.getFirstChild()); while (node != null) { if (otherNode == null) return false; short nextNodeType = node.getNodeType(); if (nextNodeType != otherNode.getNodeType()) return false; // If elements, compare if (nextNodeType == Node.ELEMENT_NODE) { if (!elementsAreEquivalent((Element)node, (Element)otherNode)) return false; } // Else if comment, compare else if (nextNodeType == Node.COMMENT_NODE) { if (!nodeValuesAreEqual(node, otherNode)) return false; } // Else punt on other node types else { return false; } node = nextNonTextNode(node.getNextSibling()); otherNode = nextNonTextNode(otherNode.getNextSibling()); } // If also at end of other children, return equal if (otherNode == null) return true; } } } else if (!otherElement.hasChildNodes()) { return attributesAreEqual(element, otherElement); } return false; } private static Node nextNonTextNode(Node node) { while (node != null && node.getNodeType() == Node.TEXT_NODE) node = node.getNextSibling(); return node; } private static boolean attributesAreEqual(Element element, Element otherElement) { NamedNodeMap attrs = element.getAttributes(); NamedNodeMap otherAttrs = otherElement.getAttributes(); if (attrs == null && otherAttrs == null) { // Return comparison of element values if there are no attributes return nodeValuesAreEqual(element, otherElement); } if (attrs.getLength() == otherAttrs.getLength()) { if (attrs.getLength() == 0) // Return comparison of element values if there are no attributes return nodeValuesAreEqual(element, otherElement); for (int i = 0; i < attrs.getLength(); i++) { Node attr = attrs.item(i); Node otherAttr = otherAttrs.getNamedItem(attr.getNodeName()); if (!nodeValuesAreEqual(attr, otherAttr)) return false; } return true; } return false; } private static boolean nodeValuesAreEqual(Node node, Node otherNode) { String value = node.getNodeValue(); String otherValue = otherNode.getNodeValue(); if (value != null && otherValue != null) { if (value.equals(otherValue)) return true; } else if (value == null && otherValue == null) return true; return false; } }