1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sf.xframe.xsddoc.util;
22
23 import org.w3c.dom.NamedNodeMap;
24 import org.w3c.dom.Node;
25 import org.w3c.dom.NodeList;
26
27 /***
28 * DOM Utility methods.
29 *
30 * @author <a href="mailto:kriede@users.sourceforge.net">Kurt Riede</a>
31 */
32 public final class DomUtil {
33
34 /***
35 * Private default constructor to prevent instantiation.
36 */
37 private DomUtil() {
38 }
39
40 /***
41 * Returns the first child node that is an element (type == ELEMENT_NODE).
42 *
43 * @param node the parent node
44 * @return the first child element or <code>null</code> if non available
45 */
46 public static Node getFirstElementChild(final Node node) {
47 final NodeList children = node.getChildNodes();
48 for (int i = 0; i < children.getLength(); i++) {
49 final Node child = children.item(i);
50 if (child.getNodeType() == Node.ELEMENT_NODE) {
51 return child;
52 }
53 }
54 return null;
55 }
56
57 /***
58 * Returns the value of a named attribute of a given node.
59 *
60 * @param node an element node
61 * @param name the name of an attribute
62 * @return the attributes value or <code>null</code> if the attribute doesn't exist.
63 */
64 public static String getAttributeValue(final Node node, final String name) {
65 try {
66 return node.getAttributes().getNamedItem(name).getNodeValue();
67 } catch (NullPointerException e) {
68 return null;
69 }
70 }
71
72 /***
73 * Removes all duplicate children from a given node.
74 *
75 * @param parent the parent node of the children to process.
76 * @return the given node
77 */
78 public static Node removeDuplicates(final Node parent) {
79 if (parent == null) {
80 return null;
81 }
82 final NodeList children = parent.getChildNodes();
83 for (int i = children.getLength() - 1; i >= 0; i--) {
84 final Node child = children.item(i);
85 if (child.getNodeType() == Node.ELEMENT_NODE) {
86 if (hasDuplicate(children, child)) {
87 parent.removeChild(child);
88 }
89 }
90 }
91 return parent;
92 }
93
94 /***
95 * Checks if a node has a duplicate within a given NodeList.
96 * The node itself might be contained in the list, but is ignored in the
97 * check.
98 *
99 * @param children the node list to search in for duplicates
100 * @param node the node to compare with
101 * @return <code>true</code> if a duplicate is found, else <code>false</code>
102 */
103 private static boolean hasDuplicate(final NodeList children, final Node node) {
104 for (int i = 0; i < children.getLength(); i++) {
105 final Node child = children.item(i);
106 if (child != node && child.getNodeType() == Node.ELEMENT_NODE) {
107 if (equals(node, child)) {
108 return true;
109 }
110 }
111 }
112 return false;
113 }
114
115 /***
116 * Checks if two nodes are equal.
117 * Two nodes are considered equal, if all the following conditions are valid:
118 * <ul>
119 * <li>both, node1 and node2 are not <code>null</code></li>
120 * <li>the names are equal</li>
121 * <li>all attributes of node1 are available in node2 and have the same value</li>
122 * </ul>
123 * <p>Text nodes are not compared.</p>
124 * <p></p>
125 *
126 * @param node1 a node to compare
127 * @param node2 another node to compare with
128 * @return <code>true</code> if the two nodes are equal,
129 * else <code>false</code>
130 */
131 private static boolean equals(final Node node1, final Node node2) {
132 if (node1 == null || node2 == null) {
133 return false;
134 }
135 if (!node1.getNodeName().equals(node2.getNodeName())) {
136 return false;
137 }
138 final NamedNodeMap attributes = node1.getAttributes();
139 for (int i = 0; i < attributes.getLength(); i++) {
140 final Node attribute1 = attributes.item(i);
141 final NamedNodeMap attributes2 = node2.getAttributes();
142 if (attributes2 == null) {
143 return false;
144 }
145 final Node attribute2 = node2.getAttributes().getNamedItem(attribute1.getNodeName());
146 if (attribute2 == null) {
147 return false;
148 }
149 if (!StringUtil.equals(attribute1.getNodeValue(), attribute2.getNodeValue())) {
150 return false;
151 }
152 }
153 return true;
154 }
155 }