diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java b/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
index cd7503484..0cea84632 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
@@ -53,14 +53,10 @@
*/
package org.apache.tools.ant.taskdefs.optional;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
+import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
+import java.util.*;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
@@ -69,17 +65,10 @@ import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.Parser;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXNotSupportedException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
+import org.xml.sax.*;
import org.xml.sax.helpers.ParserAdapter;
-/**
+/**
* The XMLValidateTask checks that an XML document is valid,
* with a SAX validating parser.
* @author Raphael Pierquin raphael.pierquin@agisphere.com
@@ -101,7 +90,7 @@ public class XMLValidateTask extends Task {
protected boolean warn = true;
protected boolean lenient = false;
protected String readerClassName = DEFAULT_XML_READER_CLASSNAME;
-
+
protected File file = null; // file to be validated
protected Vector filesets = new Vector(); // sets of file to be validated
protected Path classpath;
@@ -118,6 +107,10 @@ public class XMLValidateTask extends Task {
= new ValidatorErrorHandler(); // to report sax parsing errors
protected Hashtable features = new Hashtable();
+ /**
+ * The list of configured DTD locations
+ */
+ public ArrayList dtdLocations = new ArrayList();
/**
* Specify how parser error are to be handled.
@@ -125,7 +118,7 @@ public class XMLValidateTask extends Task {
* If set to true (default), throw a buildException if the parser yields an error.
*/
public void setFailOnError(boolean fail) {
-
+
failOnError = fail;
}
@@ -135,7 +128,7 @@ public class XMLValidateTask extends Task {
* If set to true (default), log a warn message for each SAX warn event.
*/
public void setWarn(boolean bool) {
-
+
warn = bool;
}
@@ -151,7 +144,7 @@ public class XMLValidateTask extends Task {
lenient = bool;
}
-
+
/**
* Specify the class name of the SAX parser to be used. (optional)
* @param className should be an implementation of SAX2 org.xml.sax.XMLReader
@@ -163,7 +156,7 @@ public class XMLValidateTask extends Task {
* @see org.xml.sax.Parser;
*/
public void setClassName(String className) {
-
+
readerClassName = className;
}
@@ -211,6 +204,27 @@ public class XMLValidateTask extends Task {
filesets.addElement(set);
}
+ /**
+ * Create a DTD location record. This stores the location of a DTD. The DTD is identified
+ * by its public Id. The location may either be a file location or a resource location.
+ */
+ public DTDLocation createDTD() {
+ DTDLocation dtdLocation = new DTDLocation();
+ dtdLocations.add(dtdLocation);
+
+ return dtdLocation;
+ }
+
+ protected EntityResolver getEntityResolver() {
+ LocalResolver resolver = new LocalResolver();
+
+ for (Iterator i = dtdLocations.iterator(); i.hasNext();) {
+ DTDLocation location = (DTDLocation)i.next();
+ resolver.registerDTD(location);
+ }
+ return resolver;
+ }
+
public void execute() throws BuildException {
int fileProcessed = 0;
@@ -233,13 +247,13 @@ public class XMLValidateTask extends Task {
log(errorMsg, Project.MSG_ERR);
}
}
-
+
for (int i=0; i
* log SAX parse exceptions,
* remember if an error occured
*
*/
protected class ValidatorErrorHandler implements ErrorHandler {
-
+
protected File currentFile = null;
protected String lastErrorMessage = null;
protected boolean failed = false;
-
+
public void init(File file) {
currentFile = file;
failed = false;
}
-
+
// did an error happen during last parsing ?
public boolean getFailure() {
-
+
return failed;
}
public void fatalError(SAXParseException exception) {
-
failed = true;
doLog(exception,Project.MSG_ERR);
}
public void error(SAXParseException exception) {
-
failed = true;
doLog(exception,Project.MSG_ERR);
}
-
+
public void warning(SAXParseException exception) {
- // depending on implementation, XMLReader can yield hips of warning,
+ // depending on implementation, XMLReader can yield hips of warning,
// only output then if user explicitely asked for it
if (warn)
doLog(exception,Project.MSG_WARN);
}
-
+
private void doLog(SAXParseException e, int logLevel) {
-
+
log(getMessage(e), logLevel);
}
@@ -435,4 +448,109 @@ public class XMLValidateTask extends Task {
return e.getMessage();
}
}
+
+ public static class DTDLocation {
+ private String publicId = null;
+ private String location = null;
+
+ public void setPublicId(String publicId) {
+ this.publicId = publicId;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public String getPublicId() {
+ return publicId;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+ }
+
+ private class LocalResolver
+ implements EntityResolver
+ {
+ private Hashtable fileDTDs = new Hashtable();
+ private Hashtable resourceDTDs = new Hashtable();
+ private Hashtable urlDTDs = new Hashtable();
+
+ public LocalResolver() {}
+
+ public void registerDTD(String publicId, String location) {
+ if (location == null) {
+ return;
+ }
+
+ File fileDTD = new File(location);
+ if (fileDTD.exists()) {
+ if (publicId != null) {
+ fileDTDs.put(publicId, fileDTD);
+ log("Mapped publicId " + publicId + " to file " + fileDTD, Project.MSG_VERBOSE);
+ }
+ return;
+ }
+
+ if (LocalResolver.this.getClass().getResource(location) != null) {
+ if (publicId != null) {
+ resourceDTDs.put(publicId, location);
+ log("Mapped publicId " + publicId + " to resource " + location, Project.MSG_VERBOSE);
+ }
+ }
+
+ try {
+ if (publicId != null) {
+ URL urldtd = new URL(location);
+ urlDTDs.put(publicId, urldtd);
+ }
+ } catch ( java.net.MalformedURLException e) {
+ //ignored
+ }
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException
+ {
+ File dtdFile = (File) fileDTDs.get(publicId);
+ if (dtdFile != null) {
+ try {
+ log("Resolved " + publicId + " to local file " + dtdFile, Project.MSG_VERBOSE);
+ return new InputSource(new FileInputStream(dtdFile));
+ } catch( FileNotFoundException ex ) {
+ // ignore
+ }
+ }
+
+ String dtdResourceName = (String)resourceDTDs.get(publicId);
+ if (dtdResourceName != null) {
+ InputStream is = this.getClass().getResourceAsStream(dtdResourceName);
+ if (is != null) {
+ log("Resolved " + publicId + " to local resource " + dtdResourceName, Project.MSG_VERBOSE);
+ return new InputSource(is);
+ }
+ }
+
+ URL dtdUrl = (URL) urlDTDs.get(publicId);
+ if ( dtdUrl != null ) {
+ try {
+ InputStream is = dtdUrl.openStream();
+ log("Resolved " + publicId + " to url " + dtdUrl, Project.MSG_VERBOSE);
+ return new InputSource(is);
+ } catch ( IOException ioe) {
+ //ignore
+ }
+ }
+
+ log("Could not resolve ( publicId: " + publicId + ", systemId: " + systemId + ") to a local entity",
+ Project.MSG_INFO);
+
+ return null;
+ }
+
+ public void registerDTD(DTDLocation location) {
+ registerDTD(location.getPublicId(), location.getLocation());
+ }
+ }
}