• 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

56.47
/src/main/java/com/meterware/httpunit/parsing/NekoDOMParser.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.parsing;
9

10
import com.meterware.httpunit.dom.HTMLDocumentImpl;
11
import com.meterware.httpunit.scripting.ScriptingHandler;
12

13
import java.io.IOException;
14
import java.net.URL;
15
import java.util.List;
16

17
import net.sourceforge.htmlunit.cyberneko.HTMLConfiguration;
18

19
import org.apache.xerces.parsers.AbstractDOMParser;
20
import org.apache.xerces.parsers.DOMParser;
21
import org.apache.xerces.xni.XNIException;
22
import org.apache.xerces.xni.parser.XMLDocumentFilter;
23
import org.apache.xerces.xni.parser.XMLErrorHandler;
24
import org.apache.xerces.xni.parser.XMLParseException;
25
import org.w3c.dom.Element;
26
import org.w3c.dom.html.HTMLDocument;
27
import org.xml.sax.SAXNotRecognizedException;
28
import org.xml.sax.SAXNotSupportedException;
29

30
/**
31
 * The Class NekoDOMParser.
32
 */
33
class NekoDOMParser extends DOMParser implements ScriptHandler {
34

35
    /** Error reporting feature identifier. */
36
    private static final String REPORT_ERRORS = "http://cyberneko.org/html/features/report-errors";
37

38
    /** Augmentations feature identifier. */
39
    private static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";
40

41
    /** Filters property identifier. */
42
    private static final String FILTERS = "http://cyberneko.org/html/properties/filters";
43

44
    /** Element case settings. possible values: "upper", "lower", "match" */
45
    private static final String TAG_NAME_CASE = "http://cyberneko.org/html/properties/names/elems";
46

47
    /** Attribute case settings. possible values: "upper", "lower", "no-change" */
48
    private static final String ATTRIBUTE_NAME_CASE = "http://cyberneko.org/html/properties/names/attrs";
49

50
    /** The document adapter. */
51
    private DocumentAdapter _documentAdapter;
52

53
    /**
54
     * construct a new NekoDomParser with the given adapter and url.
55
     *
56
     * @param adapter
57
     *            the adapter
58
     * @param url
59
     *            the url
60
     *
61
     * @return - the new parser patch [ 1211154 ] NekoDOMParser default to lowercase by Dan Allen patch [ 1176688 ]
62
     *         Allow configuration of neko parser properties by James Abley
63
     */
64
    static NekoDOMParser newParser(DocumentAdapter adapter, URL url) {
65
        final HTMLConfiguration configuration = new HTMLConfiguration();
1✔
66
        // note: Introduced in 1.9.9 nekohtml but doesn't apply against header but rather body and thus doesn't solve
67
        // issue with <noscript> needs.
68
        // configuration.setFeature(HTMLScanner.PARSE_NOSCRIPT_CONTENT, false);
69
        if (!HTMLParserFactory.getHTMLParserListeners().isEmpty() || HTMLParserFactory.isParserWarningsEnabled()) {
1!
70
            configuration.setErrorHandler(new ErrorHandler(url));
1✔
71
            configuration.setFeature(REPORT_ERRORS, true);
1✔
72
        }
73
        configuration.setFeature(AUGMENTATIONS, true);
1✔
74
        final ScriptFilter javaScriptFilter = new ScriptFilter(configuration);
1✔
75
        configuration.setProperty(FILTERS, new XMLDocumentFilter[] { javaScriptFilter });
1✔
76
        if (HTMLParserFactory.isPreserveTagCase()) {
1!
77
            configuration.setProperty(TAG_NAME_CASE, "match");
×
78
            configuration.setProperty(ATTRIBUTE_NAME_CASE, "no-change");
×
79
        } else {
80
            configuration.setProperty(TAG_NAME_CASE, "lower");
1✔
81
            configuration.setProperty(ATTRIBUTE_NAME_CASE, "lower");
1✔
82

83
            if (HTMLParserFactory.getForceUpperCase()) {
1!
84
                configuration.setProperty(TAG_NAME_CASE, "upper");
×
85
                configuration.setProperty(ATTRIBUTE_NAME_CASE, "upper");
×
86
            }
87
            // this is the default as of patch [ 1211154 ] ... just for people who rely on patch [ 1176688 ]
88
            if (HTMLParserFactory.getForceLowerCase()) {
1!
89
                configuration.setProperty(TAG_NAME_CASE, "lower");
×
90
                configuration.setProperty(ATTRIBUTE_NAME_CASE, "lower");
×
91
            }
92
        }
93

94
        try {
95
            final NekoDOMParser domParser = new NekoDOMParser(configuration, adapter);
1✔
96
            domParser.setFeature(AbstractDOMParser.DEFER_NODE_EXPANSION, false);
1✔
97
            if (HTMLParserFactory.isReturnHTMLDocument())
1!
98
                domParser.setProperty(AbstractDOMParser.DOCUMENT_CLASS_NAME, HTMLDocumentImpl.class.getName());
1✔
99
            javaScriptFilter.setScriptHandler(domParser);
1✔
100
            return domParser;
1✔
101
        } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
×
102
            throw new RuntimeException(e.toString());
×
103
        }
104

105
    }
106

107
    /**
108
     * Gets the current element.
109
     *
110
     * @return the current element
111
     */
112
    private Element getCurrentElement() {
113
        try {
114
            return (Element) getProperty(AbstractDOMParser.CURRENT_ELEMENT_NODE);
1✔
115
        } catch (SAXNotRecognizedException e) {
×
116
            throw new RuntimeException(AbstractDOMParser.CURRENT_ELEMENT_NODE + " property not recognized");
×
117
        } catch (SAXNotSupportedException e) {
×
118
            e.printStackTrace();
×
119
            throw new RuntimeException(AbstractDOMParser.CURRENT_ELEMENT_NODE + " property not supported");
×
120
        }
121
    }
122

123
    /**
124
     * Instantiates a new neko DOM parser.
125
     *
126
     * @param configuration
127
     *            the configuration
128
     * @param adapter
129
     *            the adapter
130
     */
131
    NekoDOMParser(HTMLConfiguration configuration, DocumentAdapter adapter) {
132
        super(configuration);
1✔
133
        _documentAdapter = adapter;
1✔
134
    }
1✔
135

136
    @Override
137
    public String getIncludedScript(String srcAttribute) {
138
        try {
139
            return _documentAdapter.getIncludedScript(srcAttribute);
1✔
140
        } catch (IOException e) {
×
141
            throw new ScriptException(e);
×
142
        }
143
    }
144

145
    @Override
146
    public boolean supportsScriptLanguage(String language) {
147
        return getScriptingHandler().supportsScriptLanguage(language);
1✔
148
    }
149

150
    @Override
151
    public String runScript(final String language, final String scriptText) {
152
        getScriptingHandler().clearCaches();
1✔
153
        return getScriptingHandler().runScript(language, scriptText);
1✔
154
    }
155

156
    /**
157
     * Gets the scripting handler.
158
     *
159
     * @return the scripting handler
160
     */
161
    private ScriptingHandler getScriptingHandler() {
162
        _documentAdapter.setDocument((HTMLDocument) getCurrentElement().getOwnerDocument());
1✔
163
        return _documentAdapter.getScriptingHandler();
1✔
164
    }
165

166
    /**
167
     * The Class ScriptException.
168
     */
169
    static class ScriptException extends RuntimeException {
170

171
        /** The Constant serialVersionUID. */
172
        private static final long serialVersionUID = 1L;
173

174
        /** The cause. */
175
        private IOException _cause;
176

177
        /**
178
         * Instantiates a new script exception.
179
         *
180
         * @param cause
181
         *            the cause
182
         */
183
        public ScriptException(IOException cause) {
×
184
            _cause = cause;
×
185
        }
×
186

187
        /**
188
         * Gets the exception.
189
         *
190
         * @return the exception
191
         */
192
        public IOException getException() {
193
            return _cause;
×
194
        }
195
    }
196
}
197

198
class ErrorHandler implements XMLErrorHandler {
199

200
    private URL _url;
201

202
    ErrorHandler(URL url) {
1✔
203
        _url = url;
1✔
204
    }
1✔
205

206
    @Override
207
    public void warning(String domain, String key, XMLParseException warningException) throws XNIException {
208
        if (HTMLParserFactory.isParserWarningsEnabled()) {
1!
209
            System.out.println("At line " + warningException.getLineNumber() + ", column "
×
210
                    + warningException.getColumnNumber() + ": " + warningException.getMessage());
×
211
        }
212

213
        List<HTMLParserListener> listeners = HTMLParserFactory.getHTMLParserListeners();
1✔
214
        for (HTMLParserListener listener : listeners) {
1✔
215
            listener.warning(_url, warningException.getMessage(), warningException.getLineNumber(),
1✔
216
                    warningException.getColumnNumber());
1✔
217
        }
1✔
218
    }
1✔
219

220
    @Override
221
    public void error(String domain, String key, XMLParseException errorException) throws XNIException {
222
        List<HTMLParserListener> listeners = HTMLParserFactory.getHTMLParserListeners();
×
223
        for (HTMLParserListener listener : listeners) {
×
224
            listener.error(_url, errorException.getMessage(), errorException.getLineNumber(),
×
225
                    errorException.getColumnNumber());
×
226
        }
×
227
    }
×
228

229
    @Override
230
    public void fatalError(String domain, String key, XMLParseException fatalError) throws XNIException {
231
        error(domain, key, fatalError);
×
232
        throw fatalError;
×
233
    }
234
}
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