Add DTD validation support to XmlParser

General Discussion on RSyntaxTextArea.

Moderator: robert

Add DTD validation support to XmlParser

Postby Tom K. » Fri May 18, 2012 11:19 pm

I was very happy to discover the XmlParser class for
generating on-the-fly squiggle underlines for XML errors.
I'd like to request a few tweaks to support DTD validation. Below is
a suggested modified version of XmlParser that has these changes:

1. Added a constructor that lets you specify an EntityResolver
for finding the DTD.
2. Added a setValidating() method.
2, Added a resolveEntity method to the private Handler class.
3. Added a check for a zero length document, to prevent generating
an error when the RSTA is empty.
4. Commented out the e.printStackTrace() call, which gets invoked
if the DTD file can't be found.

I'd like to say again how much I appreciate RSTA. It's great.

Tom K.

java code:

package org.fife.ui.rsyntaxtextarea.parser;


import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.parser.*;

* A parser for XML documents. Adds squiggle underlines for any XML errors
* found (though most XML parsers don't really have error recovery and so only
* can find one error at a time).<p>
* This class isn't actually used by RSyntaxTextArea anywhere, but you can
* install and use it yourself. Doing so is as simple as:
* <pre>
* XmlParser xmlParser = new XmlParser();
* textArea.addParser(xmlParser);
* </pre>
* Also note that a single instance of this class can be installed on
* multiple instances of <code>RSyntaxTextArea</code>.
* For a more complete XML parsing solution, see the
* <a href="">RSTALanguageSupport
* project</a>'s <code>XmlLanguageSupport</code> class.
* @author Robert Futrell
* @version 1.1
public class EditXmlParser extends AbstractParser {

private SAXParserFactory spf;
private DefaultParseResult result;
private EntityResolver entityResolver;

public EditXmlParser() {
result = new DefaultParseResult(this);
try {
spf = SAXParserFactory.newInstance();
} catch (FactoryConfigurationError fce) {


public EditXmlParser(EntityResolver entityResolver) {
this.entityResolver = entityResolver;

public void setValidating(boolean value) {

* {@inheritDoc}
public ParseResult parse(RSyntaxDocument doc, String style) {

if (doc.getLength() == 0) {
return result;

Element root = doc.getDefaultRootElement();
result.setParsedLines(0, root.getElementCount()-1);

if (spf==null) {
return result;

try {
SAXParser sp = spf.newSAXParser();
Handler handler = new Handler(doc);
DocumentReader r = new DocumentReader(doc);
InputSource input = new InputSource(r);
sp.parse(input, handler);
} catch (SAXParseException spe) {
// A fatal parse error - ignore; a ParserNotice was already created.
} catch (Exception e) {
result.addNotice(new DefaultParserNotice(this,
"Error parsing XML: " + e.getMessage(), 0, -1, -1));

return result;


* Callback notified when errors are found in the XML document. Adds a
* notice to be squiggle-underlined.
private class Handler extends DefaultHandler {

private Document doc;

private Handler(Document doc) {
this.doc = doc;

public InputSource resolveEntity(String publicId, String systemId) throws
SAXException, IOException {
if (entityResolver != null) {
return entityResolver.resolveEntity(publicId, systemId);

return super.resolveEntity(publicId, systemId);

private void doError(SAXParseException e, int level) {
int line = e.getLineNumber() - 1;
Element root = doc.getDefaultRootElement();
Element elem = root.getElement(line);
int offs = elem.getStartOffset();
int len = elem.getEndOffset() - offs;
if (line==root.getElementCount()-1) {
DefaultParserNotice pn = new DefaultParserNotice(EditXmlParser.this,
e.getMessage(), line, offs, len);

public void error(SAXParseException e) {
doError(e, ParserNotice.ERROR);

public void fatalError(SAXParseException e) {
doError(e, ParserNotice.ERROR);

public void warning(SAXParseException e) {
doError(e, ParserNotice.WARNING);


Tom K.

Re: Add DTD validation support to XmlParser

Postby robert » Sun May 20, 2012 2:36 pm

Thanks for this! I've been meaning to do something like that for awhile. I've added it in SVN and it'll be in the next release.
User avatar
Posts: 805
Joined: Sat May 10, 2008 5:16 pm

Return to Open Discussion

Who is online

Users browsing this forum: No registered users and 4 guests