Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/nu/validator/htmlparser/sax/HtmlParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ public class HtmlParser implements XMLReader {

private LexicalHandler lexicalHandler = null;

private ContentHandler treeBuildingContentHandler = null;

private LexicalHandler treeBuildingLexicalHandler = null;

private DTDHandler dtdHandler = null;

private EntityResolver entityResolver = null;
Expand Down Expand Up @@ -172,6 +176,8 @@ private void lazyInit() {
if (driver == null) {
if (streamabilityViolationPolicy == XmlViolationPolicy.ALLOW) {
this.saxTreeBuilder = new SAXTreeBuilder();
this.saxTreeBuilder.setWiretap(treeBuildingContentHandler,
treeBuildingLexicalHandler);
this.treeBuilder = this.saxTreeBuilder;
this.saxStreamer = null;
this.driver = new Driver(newTokenizer(treeBuilder, true));
Expand Down Expand Up @@ -571,6 +577,29 @@ public void setLexicalHandler(LexicalHandler handler) {
}
}

/**
* Sets handlers that get events while the parser builds a tree (that is,
* when the streamability violation policy is <code>ALLOW</code>): The
* events a streaming parse would emit, at the same points in the input,
* and with the tokenizer as their locator. So they report the same
* locations as a streaming parse does, interleaved with any errors
* reported to the error handler. They don't form a well-formed SAX
* stream, since the tree builder can move nodes after creating them;
* the handlers set with <code>setContentHandler</code> and
* <code>setLexicalHandler</code> get the events for the finished tree.
*
* @param contentHandler the content handler, or null
* @param lexicalHandler the lexical handler, or null
*/
public void setTreeBuildingWiretap(ContentHandler contentHandler,
LexicalHandler lexicalHandler) {
treeBuildingContentHandler = contentHandler;
treeBuildingLexicalHandler = lexicalHandler;
if (saxTreeBuilder != null) {
saxTreeBuilder.setWiretap(contentHandler, lexicalHandler);
}
}

/**
* @see org.xml.sax.XMLReader#setDTDHandler(org.xml.sax.DTDHandler)
*/
Expand Down
77 changes: 72 additions & 5 deletions src/nu/validator/htmlparser/sax/SAXTreeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@

package nu.validator.htmlparser.sax;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;

import nu.validator.htmlparser.impl.HtmlAttributes;
import nu.validator.htmlparser.impl.TreeBuilder;
Expand All @@ -45,23 +47,53 @@ class SAXTreeBuilder extends TreeBuilder<Element> {

private Node cachedTablePreviousSibling = null;

private ContentHandler wiretapContentHandler = null;

private LexicalHandler wiretapLexicalHandler = null;

SAXTreeBuilder() {
super();
}

/**
* Sets handlers that get, while the tree is being built, the events a
* streaming parse would emit at the same points, with the tokenizer as
* their locator.
*
* @param contentHandler the content handler, or null
* @param lexicalHandler the lexical handler, or null
*/
void setWiretap(ContentHandler contentHandler,
LexicalHandler lexicalHandler) {
wiretapContentHandler = contentHandler;
wiretapLexicalHandler = lexicalHandler;
}

@Override
protected void appendComment(Element parent, char[] buf, int start, int length) {
protected void appendComment(Element parent, char[] buf, int start, int length)
throws SAXException {
parent.appendChild(new Comment(tokenizer, buf, start, length));
if (wiretapLexicalHandler != null) {
wiretapLexicalHandler.comment(buf, start, length);
}
}

@Override
protected void appendCommentToDocument(char[] buf, int start, int length) {
protected void appendCommentToDocument(char[] buf, int start, int length)
throws SAXException {
document.appendChild(new Comment(tokenizer, buf, start, length));
if (wiretapLexicalHandler != null) {
wiretapLexicalHandler.comment(buf, start, length);
}
}

@Override
protected void appendCharacters(Element parent, char[] buf, int start, int length) {
protected void appendCharacters(Element parent, char[] buf, int start, int length)
throws SAXException {
parent.appendChild(new Characters(tokenizer, buf, start, length));
if (wiretapContentHandler != null) {
wiretapContentHandler.characters(buf, start, length);
}
}

@Override
Expand Down Expand Up @@ -91,10 +123,15 @@ protected void addAttributesToElement(Element element, HtmlAttributes attributes
* @see nu.validator.htmlparser.impl.TreeBuilder#appendDoctypeToDocument(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
protected void appendDoctypeToDocument(String name, String publicIdentifier, String systemIdentifier) {
protected void appendDoctypeToDocument(String name, String publicIdentifier, String systemIdentifier)
throws SAXException {
DTD dtd = new DTD(tokenizer, name, publicIdentifier, systemIdentifier);
dtd.setEndLocator(tokenizer);
document.appendChild(dtd);
if (wiretapLexicalHandler != null) {
wiretapLexicalHandler.startDTD(name, publicIdentifier, systemIdentifier);
wiretapLexicalHandler.endDTD();
}
}

/**
Expand Down Expand Up @@ -124,16 +161,43 @@ protected void end() throws SAXException {
document.setEndLocator(tokenizer);
cachedTable = null;
cachedTablePreviousSibling = null;
if (wiretapContentHandler != null) {
wiretapContentHandler.endDocument();
}
}

/**
* @see nu.validator.htmlparser.impl.TreeBuilder#start()
*/
@Override
protected void start(boolean fragment) {
protected void start(boolean fragment) throws SAXException {
document = new Document(tokenizer);
cachedTable = null;
cachedTablePreviousSibling = null;
if (wiretapContentHandler != null) {
wiretapContentHandler.setDocumentLocator(tokenizer);
if (!fragment) {
wiretapContentHandler.startDocument();
}
}
}

@Override
protected void elementPushed(String ns, String name, Element node)
throws SAXException {
if (wiretapContentHandler != null) {
wiretapContentHandler.startElement(ns, name, name,
node.getAttributes());
}
}

@Override
protected void elementPopped(String ns, String name, Element node)
throws SAXException {
node.setEndLocator(tokenizer);
if (wiretapContentHandler != null) {
wiretapContentHandler.endElement(ns, name, name);
}
}

@Override
Expand Down Expand Up @@ -172,6 +236,9 @@ protected Element createAndInsertFosterParentedElement(String ns, String name,
} else {
stackParent.appendChild(child);
}
if (wiretapContentHandler != null) {
wiretapContentHandler.characters(buf, start, length);
}
}

@Override protected void insertFosterParentedChild(Element child,
Expand Down
Loading