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

hazendaz / httpunit / 656

06 Dec 2025 09:11PM UTC coverage: 80.452% (+0.02%) from 80.435%
656

push

github

hazendaz
[maven-release-plugin] prepare for next development iteration

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10137 relevant lines covered (81.34%)

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
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.httpunit.parsing;
21

22
import com.meterware.httpunit.dom.HTMLDocumentImpl;
23
import com.meterware.httpunit.scripting.ScriptingHandler;
24

25
import java.io.IOException;
26
import java.net.URL;
27
import java.util.List;
28

29
import net.sourceforge.htmlunit.cyberneko.HTMLConfiguration;
30

31
import org.apache.xerces.parsers.AbstractDOMParser;
32
import org.apache.xerces.parsers.DOMParser;
33
import org.apache.xerces.xni.XNIException;
34
import org.apache.xerces.xni.parser.XMLDocumentFilter;
35
import org.apache.xerces.xni.parser.XMLErrorHandler;
36
import org.apache.xerces.xni.parser.XMLParseException;
37
import org.w3c.dom.Element;
38
import org.w3c.dom.html.HTMLDocument;
39
import org.xml.sax.SAXNotRecognizedException;
40
import org.xml.sax.SAXNotSupportedException;
41

42
/**
43
 * The Class NekoDOMParser.
44
 */
45
class NekoDOMParser extends DOMParser implements ScriptHandler {
46

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

50
    /** Augmentations feature identifier. */
51
    private static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";
52

53
    /** Filters property identifier. */
54
    private static final String FILTERS = "http://cyberneko.org/html/properties/filters";
55

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

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

62
    /** The document adapter. */
63
    private DocumentAdapter _documentAdapter;
64

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

95
            if (HTMLParserFactory.getForceUpperCase()) {
1!
96
                configuration.setProperty(TAG_NAME_CASE, "upper");
×
97
                configuration.setProperty(ATTRIBUTE_NAME_CASE, "upper");
×
98
            }
99
            // this is the default as of patch [ 1211154 ] ... just for people who rely on patch [ 1176688 ]
100
            if (HTMLParserFactory.getForceLowerCase()) {
1!
101
                configuration.setProperty(TAG_NAME_CASE, "lower");
×
102
                configuration.setProperty(ATTRIBUTE_NAME_CASE, "lower");
×
103
            }
104
        }
105

106
        try {
107
            final NekoDOMParser domParser = new NekoDOMParser(configuration, adapter);
1✔
108
            domParser.setFeature(AbstractDOMParser.DEFER_NODE_EXPANSION, false);
1✔
109
            if (HTMLParserFactory.isReturnHTMLDocument())
1!
110
                domParser.setProperty(AbstractDOMParser.DOCUMENT_CLASS_NAME, HTMLDocumentImpl.class.getName());
1✔
111
            javaScriptFilter.setScriptHandler(domParser);
1✔
112
            return domParser;
1✔
113
        } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
×
114
            throw new RuntimeException(e.toString());
×
115
        }
116

117
    }
118

119
    /**
120
     * Gets the current element.
121
     *
122
     * @return the current element
123
     */
124
    private Element getCurrentElement() {
125
        try {
126
            return (Element) getProperty(AbstractDOMParser.CURRENT_ELEMENT_NODE);
1✔
127
        } catch (SAXNotRecognizedException e) {
×
128
            throw new RuntimeException(AbstractDOMParser.CURRENT_ELEMENT_NODE + " property not recognized");
×
129
        } catch (SAXNotSupportedException e) {
×
130
            e.printStackTrace();
×
131
            throw new RuntimeException(AbstractDOMParser.CURRENT_ELEMENT_NODE + " property not supported");
×
132
        }
133
    }
134

135
    /**
136
     * Instantiates a new neko DOM parser.
137
     *
138
     * @param configuration
139
     *            the configuration
140
     * @param adapter
141
     *            the adapter
142
     */
143
    NekoDOMParser(HTMLConfiguration configuration, DocumentAdapter adapter) {
144
        super(configuration);
1✔
145
        _documentAdapter = adapter;
1✔
146
    }
1✔
147

148
    @Override
149
    public String getIncludedScript(String srcAttribute) {
150
        try {
151
            return _documentAdapter.getIncludedScript(srcAttribute);
1✔
152
        } catch (IOException e) {
×
153
            throw new ScriptException(e);
×
154
        }
155
    }
156

157
    @Override
158
    public boolean supportsScriptLanguage(String language) {
159
        return getScriptingHandler().supportsScriptLanguage(language);
1✔
160
    }
161

162
    @Override
163
    public String runScript(final String language, final String scriptText) {
164
        getScriptingHandler().clearCaches();
1✔
165
        return getScriptingHandler().runScript(language, scriptText);
1✔
166
    }
167

168
    /**
169
     * Gets the scripting handler.
170
     *
171
     * @return the scripting handler
172
     */
173
    private ScriptingHandler getScriptingHandler() {
174
        _documentAdapter.setDocument((HTMLDocument) getCurrentElement().getOwnerDocument());
1✔
175
        return _documentAdapter.getScriptingHandler();
1✔
176
    }
177

178
    /**
179
     * The Class ScriptException.
180
     */
181
    static class ScriptException extends RuntimeException {
182

183
        /** The Constant serialVersionUID. */
184
        private static final long serialVersionUID = 1L;
185

186
        /** The cause. */
187
        private IOException _cause;
188

189
        /**
190
         * Instantiates a new script exception.
191
         *
192
         * @param cause
193
         *            the cause
194
         */
195
        public ScriptException(IOException cause) {
×
196
            _cause = cause;
×
197
        }
×
198

199
        /**
200
         * Gets the exception.
201
         *
202
         * @return the exception
203
         */
204
        public IOException getException() {
205
            return _cause;
×
206
        }
207
    }
208
}
209

210
class ErrorHandler implements XMLErrorHandler {
211

212
    private URL _url;
213

214
    ErrorHandler(URL url) {
1✔
215
        _url = url;
1✔
216
    }
1✔
217

218
    @Override
219
    public void warning(String domain, String key, XMLParseException warningException) throws XNIException {
220
        if (HTMLParserFactory.isParserWarningsEnabled()) {
1!
221
            System.out.println("At line " + warningException.getLineNumber() + ", column "
×
222
                    + warningException.getColumnNumber() + ": " + warningException.getMessage());
×
223
        }
224

225
        List<HTMLParserListener> listeners = HTMLParserFactory.getHTMLParserListeners();
1✔
226
        for (HTMLParserListener listener : listeners) {
1✔
227
            listener.warning(_url, warningException.getMessage(), warningException.getLineNumber(),
1✔
228
                    warningException.getColumnNumber());
1✔
229
        }
1✔
230
    }
1✔
231

232
    @Override
233
    public void error(String domain, String key, XMLParseException errorException) throws XNIException {
234
        List<HTMLParserListener> listeners = HTMLParserFactory.getHTMLParserListeners();
×
235
        for (HTMLParserListener listener : listeners) {
×
236
            listener.error(_url, errorException.getMessage(), errorException.getLineNumber(),
×
237
                    errorException.getColumnNumber());
×
238
        }
×
239
    }
×
240

241
    @Override
242
    public void fatalError(String domain, String key, XMLParseException fatalError) throws XNIException {
243
        error(domain, key, fatalError);
×
244
        throw fatalError;
×
245
    }
246
}
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