001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License.
018     */
019    
020    package org.apache.geronimo.testsupport;
021    
022    import java.io.StringReader;
023    
024    import javax.xml.parsers.DocumentBuilder;
025    import javax.xml.parsers.DocumentBuilderFactory;
026    import javax.xml.parsers.ParserConfigurationException;
027    
028    import org.w3c.dom.Attr;
029    import org.w3c.dom.Document;
030    import org.w3c.dom.Element;
031    import org.w3c.dom.NamedNodeMap;
032    import org.w3c.dom.Node;
033    import org.w3c.dom.NodeList;
034    import org.w3c.dom.Text;
035    import org.xml.sax.InputSource;
036    
037    /**
038     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
039     */
040    public class DOMUtils {
041    
042        public static Document load(String xml) throws Exception {
043            DocumentBuilder builder = getDocumentBuilder();         
044            Document document = builder.parse(new InputSource(new StringReader(xml)));
045            return document;
046        }
047    
048        public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException {
049            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
050            builderFactory.setNamespaceAware(true);
051            DocumentBuilder builder = builderFactory.newDocumentBuilder();
052            return builder;
053        }
054        
055        public static void compareNodes(Node expected, Node actual) throws Exception {
056            if (expected.getNodeType() != actual.getNodeType()) {
057                throw new Exception("Different types of nodes: " + expected + " " + actual);
058            }
059            if (expected instanceof Document) {
060                Document expectedDoc = (Document)expected;
061                Document actualDoc = (Document)actual;
062                compareNodes(expectedDoc.getDocumentElement(), actualDoc.getDocumentElement());            
063            } else if (expected instanceof Element) {
064                Element expectedElement = (Element)expected;
065                Element actualElement = (Element)actual;
066                
067                // compare element names
068                if (!expectedElement.getLocalName().equals(actualElement.getLocalName())) {
069                    throw new Exception("Element names do not match: " + expectedElement.getLocalName() + " " + actualElement.getLocalName());
070                }   
071                // compare element ns
072                String expectedNS = expectedElement.getNamespaceURI();
073                String actualNS = actualElement.getNamespaceURI();
074                if ((expectedNS == null && actualNS != null) || (expectedNS != null && !expectedNS.equals(actualNS))) {               
075                    throw new Exception("Element namespaces names do not match: " + expectedNS + " " + actualNS);
076                }
077                
078                String elementName = "{" + expectedElement.getNamespaceURI() + "}" + actualElement.getLocalName();
079                
080                // compare attributes
081                NamedNodeMap expectedAttrs = expectedElement.getAttributes();
082                NamedNodeMap actualAttrs = actualElement.getAttributes();
083                if (countNonNamespaceAttribures(expectedAttrs) != countNonNamespaceAttribures(actualAttrs)) {
084                    throw new Exception(elementName + ": Number of attributes do not match up: " + countNonNamespaceAttribures(expectedAttrs) + " " + countNonNamespaceAttribures(actualAttrs));
085                }
086                for (int i = 0; i < expectedAttrs.getLength(); i++) {
087                    Attr expectedAttr = (Attr)expectedAttrs.item(i);
088                    if (expectedAttr.getName().startsWith("xmlns")) {
089                        continue;
090                    }
091                    Attr actualAttr = null;
092                    if (expectedAttr.getNamespaceURI() == null) {
093                        actualAttr = (Attr)actualAttrs.getNamedItem(expectedAttr.getName());
094                    } else {
095                        actualAttr = (Attr)actualAttrs.getNamedItemNS(expectedAttr.getNamespaceURI(), expectedAttr.getLocalName());
096                    }
097                    if (actualAttr == null) {
098                        throw new Exception(elementName + ": No attribute found:" + expectedAttr);
099                    }
100                    if (!expectedAttr.getValue().equals(actualAttr.getValue())) {
101                        throw new Exception(elementName + ": Attribute values do not match: " + expectedAttr.getValue() + " " + actualAttr.getValue());
102                    }
103                }            
104                
105                // compare children
106                NodeList expectedChildren = expectedElement.getChildNodes();
107                NodeList actualChildren = actualElement.getChildNodes();
108                if (expectedChildren.getLength() != actualChildren.getLength()) {
109                    throw new Exception(elementName + ": Number of children do not match up: " + expectedChildren.getLength() + " " + actualChildren.getLength());
110                }
111                for (int i = 0; i < expectedChildren.getLength(); i++) {
112                    Node expectedChild = expectedChildren.item(i);
113                    Node actualChild = actualChildren.item(i);
114                    compareNodes(expectedChild, actualChild);
115                }
116            } else if (expected instanceof Text) {
117                String expectedData = ((Text)expected).getData();
118                String actualData = ((Text)actual).getData();
119                
120                if (!expectedData.equals(actualData)) {
121                    throw new Exception("Text does not match: " + expectedData + " " + actualData);
122                }
123            }
124        }
125    
126        private static int countNonNamespaceAttribures(NamedNodeMap attrs) {
127            int n = 0;
128            for (int i = 0; i< attrs.getLength(); i++ ) {
129                Attr attr = (Attr) attrs.item(i);
130                if (!attr.getName().startsWith("xmlns")) {
131                    n++;
132                }
133            }
134            return n;
135        }
136    
137    }