/* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.xml; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.TreeMap; import junit.framework.TestCase; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; /** * XML test support utilities. * * @author Erik Brakkee */ public final class XmlUtils { /** * Disabled constructor. * */ private XmlUtils() { // Empty } /** * Checks equality of two XML documents excluding comment and processing * nodes and trimming the text of the elements. In case of problems, it * provides an xpath-like expression describing where the problem is. * * @param aMsg * @param aExpected * @param aActual */ public static void assertEquals(String aMsg, Document aExpected, Document aActual) { assertEquals( aMsg + "/" + aExpected.getDocumentElement().getLocalName(), aExpected.getDocumentElement(), aActual.getDocumentElement()); } private static List convertMap(NamedNodeMap aMap, Class aType) { List result = new ArrayList(); for (int i = 0; i < aMap.getLength(); i++) { result.add((T) aMap.item(i)); } return result; } private static List getChildElements(Element aElement) { List result = new ArrayList(); NodeList children = aElement.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node instanceof Element) { result.add((Element) node); } } return result; } private static String getDirectText(Element aElement) { String res = ""; NodeList children = aElement.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node instanceof Text) { res += node.getTextContent() + " "; } } return trim(res); } private static String trim(String aText) { return aText.trim().replaceAll("\\n", " ").replaceAll("\\s+", " "); } /** * Checks equality of two XML elements excluding comment and processing * nodes and trimming the text of the elements (including whitespace in the middle). * In case of problems, it * provides an xpath-like expression describing where the problem is. * * @param aMsg * @param aExpected * @param aActual */ private static void assertEquals(String aMsg, Element aExpected, Element aActual) { // Name. TestCase.assertEquals(aMsg + "/name()", aExpected.getLocalName(), aActual.getLocalName()); TestCase.assertEquals(aMsg + "/namespace()", aExpected.getNamespaceURI(), aActual.getNamespaceURI()); // Text TestCase.assertEquals(aMsg + "/text()", getDirectText(aExpected) , getDirectText(aActual)); // Attributes List expectedAttrs = convertMap(aExpected.getAttributes(), Attr.class); Collections.sort(expectedAttrs, new AttributeComparator()); List actualAttrs = convertMap(aActual.getAttributes(), Attr.class); Collections.sort(actualAttrs, new AttributeComparator()); TestCase.assertEquals("count(" + aMsg + "/@*)", expectedAttrs.size(), actualAttrs.size()); for (int i = 0; i < expectedAttrs.size(); i++) { String msg = aMsg + "/@" + expectedAttrs.get(i).getName(); assertEquals(msg, expectedAttrs.get(i), actualAttrs.get(i)); } // Nested elements. List expectedElems = getChildElements(aExpected); List actualElems = getChildElements(aActual); TestCase.assertEquals("count(" + aMsg + "/*)", expectedElems.size(), actualElems.size()); // determine the how-manyth element of the given name we are at. // Maps element name to the last used index (or null if not yet used) Map elementIndex = new TreeMap(); for (int i = 0; i < expectedElems.size(); i++) { String elemName = expectedElems.get(i).getLocalName(); Integer index = elementIndex.get(elemName); if (index == null) { index = 1; } else { index++; } elementIndex.put(elemName, index); String msg = aMsg + "/" + expectedElems.get(i).getLocalName() + "[" + index + "]"; assertEquals(msg, expectedElems.get(i), actualElems.get(i)); } } /** * Checks equality of two attributes. In case of problems, it provides an * xpath-like expression describing where the problem is. * * @param aMsg * @param aExpected * @param aActual */ private static void assertEquals(String aMsg, Attr aExpected, Attr aActual) { TestCase.assertEquals(aMsg + ":name", aExpected.getName(), aActual.getName()); TestCase.assertEquals(aMsg + ":value", aExpected.getValue(), aActual.getValue()); } /** * Comparator which compares attributes by name. */ private static final class AttributeComparator implements Comparator, Serializable { private static final long serialVersionUID = 7897287273519886301L; /* * (non-Javadoc) * * @see java.util.Comparator#compare(T, T) */ public int compare(Attr aAttribute1, Attr aAttribute2) { return aAttribute1.getName().compareTo(aAttribute2.getName()); } } }