001    /*
002     * Created on Apr 3, 2009
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2009 the original author or authors.
015     */
016    package org.fest.swing.junit.xml;
017    
018    import static org.fest.util.Objects.HASH_CODE_PRIME;
019    import static org.fest.util.Objects.hashCodeFor;
020    import static org.fest.util.Strings.concat;
021    
022    import org.w3c.dom.*;
023    
024    /**
025     * Understands a DOM-based XML element. This class is intended for internal use only. It is just a thin wrapper around
026     * a DOM <code>{@link Element}</code>. It only provides the necessary functionality needed by the FEST-Swing JUnit
027     * extension.
028     *
029     * @author Alex Ruiz
030     */
031    public class XmlNode {
032    
033      private final Element target;
034    
035      /**
036       * Creates a new </code>{@link XmlNode}</code>.
037       * @param target the underlying DOM element.
038       */
039      protected XmlNode(Element target) {
040        this.target = target;
041      }
042    
043      /**
044       * Creates and adds a new XML node to this node.
045       * @param name the name of the node to add.
046       * @return the created node.
047       */
048      public XmlNode addNewNode(String name) {
049        return new XmlNode(createAndAddChild(name));
050      }
051    
052      /**
053       * Creates and adds a new XML node to this node.
054       * @param name the name of the node to add.
055       * @param attributes the attributes of the node to add.
056       * @return the created node.
057       */
058      public XmlNode addNewNode(String name, XmlAttributes attributes) {
059        Element e = createAndAddChild(name);
060        for (XmlAttribute a : attributes) addAttribute(e, a);
061        return new XmlNode(e);
062      }
063    
064      private Element createAndAddChild(String name) {
065        Element e = document().createElement(name);
066        target.appendChild(e);
067        return e;
068      }
069    
070      /**
071       * Adds a CDATA section to this node.
072       * @param data the data for the CDATA section to create.
073       */
074      public void addCdata(String data) {
075        CDATASection s = document().createCDATASection(data);
076        target.appendChild(s);
077      }
078    
079      /**
080       * Adds a text node to this node.
081       * @param text the text of the new text node.
082       */
083      public void addText(String text) {
084        Text textNode = document().createTextNode(text);
085        target.appendChild(textNode);
086      }
087    
088      private Document document() {
089        return target.getOwnerDocument();
090      }
091    
092      /**
093       * Adds an attribute to this node.
094       * @param a the attribute to add.
095       */
096      public void addAttribute(XmlAttribute a) {
097        addAttribute(target, a);
098      }
099    
100      /**
101       * Adds one or more attributes to this node.
102       * @param attributes the attribute(s) to add to this node.
103       */
104      public void addAttributes(XmlAttribute...attributes) {
105        for (XmlAttribute a : attributes) addAttribute(target, a);
106      }
107    
108      private static void addAttribute(Element e, XmlAttribute a) {
109        e.setAttribute(a.name(), a.value());
110      }
111    
112      /**
113       * Returns the underlying DOM <code>{@link Element}</code>.
114       * @return the underlying DOM element.
115       */
116      public Element target() { return target; }
117    
118      /**
119       * Returns the parent node of this node.
120       * @return the parent node of this node.
121       */
122      public XmlNode parentNode() {
123        return xmlNodeFrom(target.getParentNode());
124      }
125    
126      /**
127       * Returns the number of children in this node.
128       * @return the number of children in this node.
129       */
130      public int size() {
131        return target.getChildNodes().getLength();
132      }
133    
134      /**
135       * Returns the child at the given index.
136       * @param index the given index.
137       * @return the child at the given index.
138       */
139      public XmlNode child(int index) {
140        return xmlNodeFrom(target.getChildNodes().item(index));
141      }
142    
143      private static XmlNode xmlNodeFrom(Node n) {
144        if (!(n instanceof Element)) return null;
145        return new XmlNode((Element)n);
146      }
147    
148      /**
149       * Returns the value of the given attribute, or an empty <code>String</code> if this node does not contain an
150       * attribute with the given name.
151       * @param name the name of the attribute we are looking for.
152       * @return the value of the attribute with the given name, or an empty <code>String</code> if this node does not
153       * contain a matching attribute.
154       */
155      public String valueOfAttribute(String name) {
156        return target.getAttribute(name);
157      }
158    
159      /**
160       * Returns the name of this node.
161       * @return the name of this node.
162       */
163      public String name() {
164        return target.getNodeName();
165      }
166    
167      /**
168       * Returns the text content of this node.
169       * @return the text content of this node.
170       */
171      public String text() {
172        return target.getTextContent();
173      }
174    
175      /**
176       * Returns the number of attributes in this node.
177       * @return the number of attributes in this node.
178       */
179      public int attributeCount() {
180        return target.getAttributes().getLength();
181      }
182    
183      @Override public boolean equals(Object obj) {
184        if (this == obj) return true;
185        if (obj == null) return false;
186        if (getClass() != obj.getClass()) return false;
187        XmlNode other = (XmlNode) obj;
188        return target.isEqualNode(other.target);
189      }
190    
191      @Override public int hashCode() {
192        int result = 1;
193        result = HASH_CODE_PRIME * result + hashCodeFor(name());
194        return result;
195      }
196    
197      @Override public String toString() {
198        return concat(
199            getClass().getSimpleName(), "[",
200            "target=", target, "]"
201        );
202      }
203    }