• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 755

14 Feb 2026 07:14PM UTC coverage: 80.526%. Remained the same
755

push

github

hazendaz
[ci] Fix badge

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10124 relevant lines covered (81.44%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.34
/src/main/java/com/meterware/httpunit/NodeUtils.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2000-2026 Russell Gold
6
 * Copyright 2021-2000 hazendaz
7
 */
8
package com.meterware.httpunit;
9

10
import com.meterware.httpunit.parsing.HTMLParserFactory;
11

12
import java.util.Iterator;
13
import java.util.ListIterator;
14
import java.util.Stack;
15

16
import org.w3c.dom.Element;
17
import org.w3c.dom.NamedNodeMap;
18
import org.w3c.dom.Node;
19
import org.w3c.dom.NodeList;
20

21
/**
22
 * Some common utilities for manipulating DOM nodes.
23
 **/
24
public class NodeUtils {
×
25

26
    /**
27
     * get the attribute with the given name from the given node as an int value.
28
     *
29
     * @param node
30
     *            - the node to look in
31
     * @param attributeName
32
     *            - the attribute's name to look for
33
     * @param defaultValue
34
     *            the default value
35
     *
36
     * @return - the value - defaultValue as default
37
     */
38
    public static int getAttributeValue(Node node, String attributeName, int defaultValue) {
39
        NamedNodeMap nnm = node.getAttributes();
1✔
40
        Node attribute = nnm.getNamedItem(attributeName);
1✔
41
        if (attribute == null) {
1✔
42
            return defaultValue;
1✔
43
        }
44
        try {
45
            return Integer.parseInt(attribute.getNodeValue());
1✔
46
        } catch (NumberFormatException e) {
×
47
            return defaultValue;
×
48
        }
49
    }
50

51
    /**
52
     * get the attribute with the given name from the given node.
53
     *
54
     * @param node
55
     *            - the node to look in
56
     * @param attributeName
57
     *            - the attribute's name to look for
58
     *
59
     * @return - the value - "" as default
60
     */
61
    public static String getNodeAttribute(Node node, String attributeName) {
62
        return getNodeAttribute(node, attributeName, "");
1✔
63
    }
64

65
    /**
66
     * get the attribute with the given name from the given node.
67
     *
68
     * @param node
69
     *            - the node to look in
70
     * @param attributeName
71
     *            - the attribute's name to look for
72
     * @param defaultValue
73
     *            the default value
74
     *
75
     * @return - the value - defaultValue as default
76
     */
77
    public static String getNodeAttribute(Node node, String attributeName, String defaultValue) {
78
        NamedNodeMap attributes = node.getAttributes();
1✔
79
        if (attributes == null) {
1✔
80
            return defaultValue;
1✔
81
        }
82

83
        Node attribute = attributes.getNamedItem(attributeName);
1✔
84
        return attribute == null ? defaultValue : attribute.getNodeValue();
1✔
85
    }
86

87
    /**
88
     * set the attribute with the given attribute to the given value in the given node.
89
     *
90
     * @param node
91
     *            the node
92
     * @param attributeName
93
     *            - the attribute's name to look for
94
     * @param value
95
     *            - the value to set
96
     */
97
    static void setNodeAttribute(Node node, String attributeName, String value) {
98
        ((Element) node).setAttributeNS(null, attributeName, value);
1✔
99
    }
1✔
100

101
    /**
102
     * remove the given attribute from the given node based on the attribute's name.
103
     *
104
     * @param node
105
     *            the node
106
     * @param attributeName
107
     *            the attribute name
108
     */
109
    static void removeNodeAttribute(Node node, String attributeName) {
110
        ((Element) node).removeAttribute(attributeName);
×
111
    }
×
112

113
    /**
114
     * check whether the given Attribute in the Node is Present.
115
     *
116
     * @param node
117
     *            - the node to check
118
     * @param attributeName
119
     *            - the attribute name to check
120
     *
121
     * @return true if the attribute is present
122
     */
123
    public static boolean isNodeAttributePresent(Node node, final String attributeName) {
124
        return node.getAttributes().getNamedItem(attributeName) != null;
1✔
125
    }
126

127
    /**
128
     * common Node action methods.
129
     */
130
    interface NodeAction {
131

132
        /**
133
         * Does appropriate processing on specified element. Will return false if the subtree below the element should
134
         * be skipped.
135
         *
136
         * @param traversal
137
         *            the traversal
138
         * @param element
139
         *            the element
140
         *
141
         * @return true, if successful
142
         */
143
        boolean processElement(PreOrderTraversal traversal, Element element);
144

145
        /**
146
         * Processes a text node.
147
         *
148
         * @param traversal
149
         *            the traversal
150
         * @param textNode
151
         *            the text node
152
         */
153
        void processTextNode(PreOrderTraversal traversal, Node textNode);
154
    }
155

156
    /**
157
     * Converts the DOM trees rooted at the specified nodes to text, ignoring any HTML tags.
158
     *
159
     * @param rootNodes
160
     *            the root nodes
161
     *
162
     * @return the string
163
     */
164
    public static String asText(NodeList rootNodes) {
165
        final StringBuilder sb = new StringBuilder(HttpUnitUtils.DEFAULT_TEXT_BUFFER_SIZE);
1✔
166
        NodeAction action = new NodeAction() {
1✔
167
            @Override
168
            public boolean processElement(PreOrderTraversal traversal, Element node) {
169
                String nodeName = node.getNodeName();
1✔
170
                if (nodeName.equalsIgnoreCase("p") || nodeName.equalsIgnoreCase("br")
1!
171
                        || nodeName.equalsIgnoreCase("tr")) {
1✔
172
                    sb.append("\n");
1✔
173
                } else if (nodeName.equalsIgnoreCase("td") || nodeName.equalsIgnoreCase("th")) {
1!
174
                    sb.append(" | ");
1✔
175
                } else if (nodeName.equalsIgnoreCase("img") && HttpUnitOptions.getImagesTreatedAsAltText()) {
1✔
176
                    sb.append(getNodeAttribute(node, "alt"));
1✔
177
                }
178
                return true;
1✔
179
            }
180

181
            @Override
182
            public void processTextNode(PreOrderTraversal traversal, Node textNode) {
183
                sb.append(HTMLParserFactory.getHTMLParser().getCleanedText(textNode.getNodeValue()));
1✔
184
            }
1✔
185
        };
186
        new PreOrderTraversal(rootNodes).perform(action);
1✔
187
        return sb.toString();
1✔
188
    }
189

190
    /**
191
     * The Class PreOrderTraversal.
192
     */
193
    static class PreOrderTraversal {
194

195
        /** The pending nodes. */
196
        private Stack _pendingNodes = new Stack();
1✔
197

198
        /** The traversal context. */
199
        private Stack _traversalContext = new Stack();
1✔
200

201
        /** The Constant POP_CONTEXT. */
202
        private static final Object POP_CONTEXT = new Object();
1✔
203

204
        /**
205
         * Instantiates a new pre order traversal.
206
         *
207
         * @param rootNodes
208
         *            the root nodes
209
         */
210
        public PreOrderTraversal(NodeList rootNodes) {
1✔
211
            pushNodeList(rootNodes);
1✔
212
        }
1✔
213

214
        /**
215
         * Instantiates a new pre order traversal.
216
         *
217
         * @param rootNode
218
         *            the root node
219
         */
220
        public PreOrderTraversal(Node rootNode) {
1✔
221
            pushNodeList(rootNode.getLastChild());
1✔
222
        }
1✔
223

224
        /**
225
         * Push base context.
226
         *
227
         * @param context
228
         *            the context
229
         */
230
        public void pushBaseContext(Object context) {
231
            _traversalContext.push(context);
1✔
232
        }
1✔
233

234
        /**
235
         * Push context.
236
         *
237
         * @param context
238
         *            the context
239
         */
240
        public void pushContext(Object context) {
241
            _traversalContext.push(context);
1✔
242
            _pendingNodes.push(POP_CONTEXT);
1✔
243
        }
1✔
244

245
        /**
246
         * Gets the contexts.
247
         *
248
         * @return the contexts
249
         */
250
        public Iterator getContexts() {
251
            Stack stack = _traversalContext;
1✔
252
            return getTopDownIterator(stack);
1✔
253
        }
254

255
        /**
256
         * Gets the root context.
257
         *
258
         * @return the root context
259
         */
260
        public Object getRootContext() {
261
            return _traversalContext.firstElement();
×
262
        }
263

264
        /**
265
         * Gets the top down iterator.
266
         *
267
         * @param stack
268
         *            the stack
269
         *
270
         * @return the top down iterator
271
         */
272
        private Iterator getTopDownIterator(final Stack stack) {
273
            return new Iterator() {
1✔
274
                private ListIterator _forwardIterator = stack.listIterator(stack.size());
1✔
275

276
                @Override
277
                public boolean hasNext() {
278
                    return _forwardIterator.hasPrevious();
1✔
279
                }
280

281
                @Override
282
                public Object next() {
283
                    return _forwardIterator.previous();
1✔
284
                }
285

286
                @Override
287
                public void remove() {
288
                    _forwardIterator.remove();
×
289
                }
×
290
            };
291
        }
292

293
        /**
294
         * Returns the most recently pushed context which implements the specified class. Will return null if no
295
         * matching context is found.
296
         *
297
         * @param matchingClass
298
         *            the matching class
299
         *
300
         * @return the closest context
301
         */
302
        public Object getClosestContext(Class matchingClass) {
303
            for (int i = _traversalContext.size() - 1; i >= 0; i--) {
1✔
304
                Object o = _traversalContext.elementAt(i);
1✔
305
                if (matchingClass.isInstance(o)) {
1✔
306
                    return o;
1✔
307
                }
308
            }
309
            return null;
1✔
310
        }
311

312
        /**
313
         * Perform.
314
         *
315
         * @param action
316
         *            the action
317
         */
318
        public void perform(NodeAction action) {
319
            while (!_pendingNodes.empty()) {
1✔
320
                final Object object = _pendingNodes.pop();
1✔
321
                if (object == POP_CONTEXT) {
1✔
322
                    _traversalContext.pop();
1✔
323
                } else {
324
                    Node node = (Node) object;
1✔
325
                    if (node.getNodeType() == Node.TEXT_NODE) {
1✔
326
                        action.processTextNode(this, node);
1✔
327
                    } else if (node.getNodeType() != Node.ELEMENT_NODE) {
1!
328
                        continue;
×
329
                    } else {
330
                        action.processElement(this, (Element) node);
1✔
331
                    }
332
                    pushNodeList(node.getLastChild());
1✔
333
                }
334
            }
1✔
335
        }
1✔
336

337
        /**
338
         * Push node list.
339
         *
340
         * @param nl
341
         *            the nl
342
         */
343
        private void pushNodeList(NodeList nl) {
344
            if (nl != null) {
1!
345
                for (int i = nl.getLength() - 1; i >= 0; i--) {
1✔
346
                    _pendingNodes.push(nl.item(i));
1✔
347
                }
348
            }
349
        }
1✔
350

351
        /**
352
         * Push node list.
353
         *
354
         * @param lastChild
355
         *            the last child
356
         */
357
        private void pushNodeList(Node lastChild) {
358
            for (Node node = lastChild; node != null; node = node.getPreviousSibling()) {
1✔
359
                _pendingNodes.push(node);
1✔
360
            }
361
        }
1✔
362
    }
363

364
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc