001: package com.meterware.httpunit.parsing;
002:
003: import com.meterware.httpunit.scripting.ScriptableDelegate;
004:
005: import java.net.URL;
006: import java.io.IOException;
007: import java.util.Enumeration;
008:
009: import org.cyberneko.html.HTMLConfiguration;
010: import org.apache.xerces.xni.parser.XMLDocumentFilter;
011: import org.apache.xerces.xni.parser.XMLErrorHandler;
012: import org.apache.xerces.xni.parser.XMLParseException;
013: import org.apache.xerces.xni.XNIException;
014: import org.xml.sax.SAXNotRecognizedException;
015: import org.xml.sax.SAXNotSupportedException;
016: import org.w3c.dom.Node;
017: import org.w3c.dom.Document;
018:
019: /**
020: *
021: *
022: * @author <a href="russgold@acm.org">Russell Gold</a>
023: * @author <a href="mailto:Artashes.Aghajanyan@lycos-europe.com">Artashes Aghajanyan</a>
024: **/
025: class NekoDOMParser extends org.apache.xerces.parsers.DOMParser {
026:
027: private static final String HTML_DOCUMENT_CLASS_NAME = "org.apache.html.dom.HTMLDocumentImpl";
028:
029: /** Error reporting feature identifier. */
030: private static final String REPORT_ERRORS = "http://cyberneko.org/html/features/report-errors";
031:
032: /** Augmentations feature identifier. */
033: private static final String AUGMENTATIONS = "http://cyberneko.org/html/features/augmentations";
034:
035: /** Filters property identifier. */
036: private static final String FILTERS = "http://cyberneko.org/html/properties/filters";
037:
038: /** Element case settings. possible values: "upper", "lower", "match" */
039: private static final String TAG_NAME_CASE = "http://cyberneko.org/html/properties/names/elems";
040:
041: /** Attribute case settings. possible values: "upper", "lower", "no-change" */
042: private static final String ATTRIBUTE_NAME_CASE = "http://cyberneko.org/html/properties/names/attrs";
043:
044: private DocumentAdapter _documentAdapter;
045:
046: /** The node representing the document. **/
047: private Node _documentNode;
048:
049: static NekoDOMParser newParser(DocumentAdapter adapter, URL url) {
050: final HTMLConfiguration configuration = new HTMLConfiguration();
051: if (!HTMLParserFactory.getHTMLParserListeners().isEmpty()
052: || HTMLParserFactory.isParserWarningsEnabled()) {
053: configuration.setErrorHandler(new ErrorHandler(url));
054: configuration.setFeature(REPORT_ERRORS, true);
055: }
056: configuration.setFeature(AUGMENTATIONS, true);
057: final ScriptFilter javaScriptFilter = new ScriptFilter(
058: configuration);
059: configuration.setProperty(FILTERS,
060: new XMLDocumentFilter[] { javaScriptFilter });
061: if (HTMLParserFactory.isPreserveTagCase()) {
062: configuration.setProperty(TAG_NAME_CASE, "match");
063: configuration.setProperty(ATTRIBUTE_NAME_CASE, "no-change");
064: }
065:
066: try {
067: final NekoDOMParser domParser = new NekoDOMParser(
068: configuration, adapter);
069: domParser.setFeature(DEFER_NODE_EXPANSION, false);
070: if (HTMLParserFactory.isReturnHTMLDocument())
071: domParser.setProperty(DOCUMENT_CLASS_NAME,
072: HTML_DOCUMENT_CLASS_NAME);
073: javaScriptFilter.setParser(domParser);
074: return domParser;
075: } catch (SAXNotRecognizedException e) {
076: throw new RuntimeException(e.toString());
077: } catch (SAXNotSupportedException e) {
078: throw new RuntimeException(e.toString());
079: }
080:
081: }
082:
083: ScriptableDelegate getScriptableDelegate() {
084: if (_documentNode == null) {
085: Node node = getCurrentElementNode();
086: while (!(node instanceof Document))
087: node = node.getParentNode();
088: _documentNode = node;
089: }
090: _documentAdapter.setRootNode(_documentNode);
091: return _documentAdapter.getScriptableObject();
092: }
093:
094: private Node getCurrentElementNode() {
095: try {
096: final Node node = (Node) getProperty(CURRENT_ELEMENT_NODE);
097: return node;
098: } catch (SAXNotRecognizedException e) {
099: throw new RuntimeException(CURRENT_ELEMENT_NODE
100: + " property not recognized");
101: } catch (SAXNotSupportedException e) {
102: e.printStackTrace();
103: throw new RuntimeException(CURRENT_ELEMENT_NODE
104: + " property not supported");
105: }
106: }
107:
108: String getIncludedScript(String srcAttribute) {
109: try {
110: return _documentAdapter.getIncludedScript(srcAttribute);
111: } catch (IOException e) {
112: throw new ScriptException(e);
113: }
114: }
115:
116: NekoDOMParser(HTMLConfiguration configuration,
117: DocumentAdapter adapter) {
118: super (configuration);
119: _documentAdapter = adapter;
120: }
121:
122: static class ScriptException extends RuntimeException {
123: private IOException _cause;
124:
125: public ScriptException(IOException cause) {
126: _cause = cause;
127: }
128:
129: public IOException getException() {
130: return _cause;
131: }
132: }
133: }
134:
135: class ErrorHandler implements XMLErrorHandler {
136:
137: private URL _url = null;
138:
139: ErrorHandler(URL url) {
140: _url = url;
141: }
142:
143: public void warning(String domain, String key,
144: XMLParseException warningException) throws XNIException {
145: if (HTMLParserFactory.isParserWarningsEnabled()) {
146: System.out.println("At line "
147: + warningException.getLineNumber() + ", column "
148: + warningException.getColumnNumber() + ": "
149: + warningException.getMessage());
150: }
151:
152: Enumeration listeners = HTMLParserFactory
153: .getHTMLParserListeners().elements();
154: while (listeners.hasMoreElements()) {
155: ((HTMLParserListener) listeners.nextElement()).warning(
156: _url, warningException.getMessage(),
157: warningException.getLineNumber(), warningException
158: .getColumnNumber());
159: }
160: }
161:
162: public void error(String domain, String key,
163: XMLParseException errorException) throws XNIException {
164: Enumeration listeners = HTMLParserFactory
165: .getHTMLParserListeners().elements();
166: while (listeners.hasMoreElements()) {
167: ((HTMLParserListener) listeners.nextElement()).error(_url,
168: errorException.getMessage(), errorException
169: .getLineNumber(), errorException
170: .getColumnNumber());
171: }
172: }
173:
174: public void fatalError(String domain, String key,
175: XMLParseException fatalError) throws XNIException {
176: error(domain, key, fatalError);
177: throw fatalError;
178: }
179: }
|