Browse Source

<schemavalidate>. Because I can never get the settings right.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277707 13f79535-47bb-0310-9956-ffa450edef68
master
Steve Loughran 20 years ago
parent
commit
2bf7351182
12 changed files with 953 additions and 37 deletions
  1. +310
    -0
      docs/manual/OptionalTasks/schemavalidate.html
  2. +3
    -2
      docs/manual/optionaltasklist.html
  3. +30
    -0
      src/etc/testcases/taskdefs/optional/schemavalidate.xml
  4. +22
    -0
      src/etc/testcases/taskdefs/optional/xml/doc-in-ns.xsd
  5. +7
    -0
      src/etc/testcases/taskdefs/optional/xml/endpiece-ns-no-location.xml
  6. +2
    -4
      src/etc/testcases/taskdefs/optional/xml/endpiece.xml
  7. +13
    -0
      src/etc/testcases/taskdefs/optional/xmlvalidate.xml
  8. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/defaults.properties
  9. +361
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java
  10. +94
    -31
      src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
  11. +47
    -0
      src/main/org/apache/tools/ant/util/XmlConstants.java
  12. +63
    -0
      src/testcases/org/apache/tools/ant/taskdefs/optional/SchemaValidateTest.java

+ 310
- 0
docs/manual/OptionalTasks/schemavalidate.html View File

@@ -0,0 +1,310 @@
<html>

<head>
<title>SchemaValidate Task</title>
</head>

<body>

<h2><a name="schemavalidate">SchemaValidate</a></h2>
<h3>Description</h3>

<p>This task validates XML files described by an XML Schema.
The task extends the XmlValidate task with XSD-specific features.</p>
<ol>
<li>The parser is created validating and namespace aware
</li>
<li>Validation is turned on.</li>
<li>and Schema validation is turned on.</li>
<li>Any default schema supplied is used as the no-namespace schema
<li>All nested schema declarations are turned into the list of namespace-url
bindings for schema lookup.
</ol>

Note that nested catalogs are still used for lookup of the URLs given as the
sources of schema documents, so you can still delegate lookup to a catalog, you
just need to list all schema URIs and their URL equivalents.

<p>This task supports the use of nested
<li><a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a> elements</li>
<li> <tt>&lt;schema&gt;</tt> elements, that bind a namespace URI to a URL or a
local filename.
<li><tt>&lt;dtd&gt;</tt> elements which are used to resolve DTDs and entities.</li>
<li><tt>&lt;attribute&gt;</tt> elements which are used to set features on the parser.
These can be any number of
<a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a>
or other features that your parser may support.</li>
<li><tt>&lt;property&gt;</tt> elements, containing string properties
</p>

<p>
The task only supports SAX2 or later parsers: it is an error to specify a SAX1
parser.


<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Attribute</b></td>
<td valign="top"><b>Description</b></td>
<td align="center" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">file</td>
<td valign="top">the file(s) you want to check. (optionally can use an embedded fileset)</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">defaultSchemaFile</td>
<td valign="top">
filename of a no-namespace XSD file to provide the
schema for no-namespace XML content.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">noNamespaceURL</td>
<td valign="top">
URL of a no-namespace XSD file to provide the
schema for no-namespace XML content.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">noNamespaceFile</td>
<td valign="top">
filename of a no-namespace XSD file to provide the
schema for no-namespace XML content.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">fullchecking</td>
<td valign="top">
enable full schema checking. Slow but strict.
</td>
<td valign="top" align="center">No - default true</td>
</tr>
<tr>
<td valign="top">lenient</td>
<td valign="top">
if true, only check the XML document is well formed
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">classname</td>
<td valign="top">the parser to use.</td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">classpathref</td>
<td valign="top">where to find the parser class.
Optionally can use an embedded <tt>&lt;classpath&gt;</tt> element.</td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">failonerror</td>
<td valign="top">fails on a error if set to true (defaults to true).</td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">warn</td>
<td valign="top">log parser warn events.</td>
<td align="center" valign="top">No</td>
</tr>
</table>

<h3><a name="nested">Nested Elements</a></h3>


<h4>schema</h4>
<p>
Identify the name and location of a schema that may be used in validating
the document(s).
</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td width="12%" valign="top"><b>Attribute</b></td>
<td width="78%" valign="top"><b>Description</b></td>
<td width="10%" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">namespace</td>
<td valign="top">URI of the schema namespace</td>
<td align="center" valign="top">Yes</td>
</tr>
<tr>
<td valign="top">url</td>
<td valign="top">URL of the schema</td>
<td align="center" valign="top">One of url or file is required</td>
</tr>
<tr>
<td valign="top">file</td>
<td valign="top">file of the schema</td>
<td align="center" valign="top">One of url or file is required</td>
</tr>
</table>

<h4>dtd</h4>
<p>
<tt>&lt;dtd&gt;</tt> is used to specify different locations for DTD resolution.
</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td width="12%" valign="top"><b>Attribute</b></td>
<td width="78%" valign="top"><b>Description</b></td>
<td width="10%" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">publicId</td>
<td valign="top">Public ID of the DTD to resolve</td>
<td align="center" valign="top">Yes</td>
</tr>
<tr>
<td valign="top">location</td>
<td valign="top">Location of the DTD to use, which can be a file,
a resource, or a URL</td>
<td align="center" valign="top">Yes</td>
</tr>
</table>
<h4>xmlcatalog</h4>
<p>The <a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a>
element is used to perform entity resolution.</p>
<h4>attribute</h4>
<p>The <tt>&lt;attribute&gt;</tt> element is used to set parser features.<br>
Features usable with the xerces parser are defined here :
<a href="http://xml.apache.org/xerces-j/features.html">Setting features</a><br>

SAX features are defined here:
<a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a><br>
</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td width="12%" valign="top"><b>Attribute</b></td>
<td width="78%" valign="top"><b>Description</b></td>
<td width="10%" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">name</td>
<td valign="top">The name of the feature</td>
<td align="center" valign="top">Yes</td>
</tr>
<tr>
<td valign="top">value</td>
<td valign="top">The boolean value of the feature</td>
<td align="center" valign="top">Yes</td>
</tr>
</table>
</p>

<h4>property</h4>
<p>The <tt>&lt;property&gt;</tt> element is used to set properties.
These properties are defined here for the xerces XML parser implementation :
<a href="http://xml.apache.org/xerces-j/properties.html">XML Parser properties</a>
Properties can be used to set the schema used to validate the XML file.
</p>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td width="12%" valign="top"><b>Attribute</b></td>
<td width="78%" valign="top"><b>Description</b></td>
<td width="10%" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">name</td>
<td valign="top">The name of the feature</td>
<td align="center" valign="top">Yes</td>
</tr>
<tr>
<td valign="top">value</td>
<td valign="top">The string value of the property</td>
<td align="center" valign="top">Yes</td>
</tr>
</table>
</p>


<h3>Examples</h3>
<pre>
&lt;xmlvalidate file="toto.xml"/&gt;
</pre>
Validate toto.xml
<pre>
&lt;xmlvalidate failonerror="no" lenient="yes" warn="yes"
classname="org.apache.xerces.parsers.SAXParser"&gt;
classpath="lib/xerces.jar"&gt;
&lt;fileset dir="src" includes="style/*.xsl"/&gt;
&lt;/xmlvalidate&gt;
</pre>
Validate all .xsl files in src/style, but only warn if there is an error, rather than
halt the build.
<pre>

&lt;xmlvalidate file="struts-config.xml" warn="false"&gt;
&lt;dtd publicId="-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
location="struts-config_1_0.dtd"/&gt;
&lt;/xmlvalidate&gt;
</pre>

Validate a struts configuration, using a local copy of the DTD.
<pre>
&lt;xmlvalidate failonerror="no"&gt;
&lt;fileset dir="${project.dir}" includes="**/*.xml"/&gt;
&lt;xmlcatalog refid="mycatalog"/&gt;
&lt;/xmlvalidate&gt;
</pre>

Scan all XML files in the project, using a predefined catalog to map URIs to local files.
<pre>
&lt;xmlvalidate failonerror="no"&gt;
&lt;fileset dir="${project.dir}" includes="**/*.xml"/&gt;
&lt;xmlcatalog&gt;
&lt;dtd
publicId=&quot;-//ArielPartners//DTD XML Article V1.0//EN&quot;
location=&quot;com/arielpartners/knowledgebase/dtd/article.dtd&quot;/&gt;
&lt;/xmlcatalog&gt;
&lt;/xmlvalidate&gt;
</pre>
Scan all XML files in the project, using the catalog defined inline.

<pre>
&lt;xmlvalidate failonerror="yes" lenient="no" warn="yes"&gt;
&lt;fileset dir="xml" includes="**/*.xml"/&gt;
&lt;attribute name="http://xml.org/sax/features/validation" value="true"/&gt;
&lt;attribute name="http://apache.org/xml/features/validation/schema" value="true"/&gt;
&lt;attribute name="http://xml.org/sax/features/namespaces" value="true"/&gt;
&lt;/xmlvalidate&gt;
</pre>
Validate all .xml files in xml directory with the parser configured to perform schema validation. Note: The parser must support the
<pre>http://apache.org/xml/features/validation/schema</pre> feature.

<br>
<pre>
<!-- Converts path to URL format -->
&lt;pathconvert dirsep="/" property="xsd.file"&gt;
&lt;path&gt;
&lt;pathelement location="xml/doc.xsd"/&gt;
&lt;/path&gt;
&lt;/pathconvert&gt;

&lt;xmlvalidate file="xml/endpiece-noSchema.xml" lenient="false"
failonerror="true" warn="true"&gt;
&lt;attribute name="http://apache.org/xml/features/validation/schema"
value="true"/&gt;
&lt;attribute name="http://xml.org/sax/features/namespaces" value="true"/&gt;
&lt;property
name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
value="${xsd.file}"/&gt;
&lt;/xmlvalidate&gt;
</pre>
<br>
Validate the file xml/endpiece-noSchema.xml against the schema xml/doc.xsd.
<br>
<hr>
<p align="center">Copyright &copy; 2001-2002,2004 The Apache Software Foundation. All rights
Reserved.</p>

</body>
</html>


+ 3
- 2
docs/manual/optionaltasklist.html View File

@@ -56,11 +56,12 @@
<a href="OptionalTasks/replaceregexp.html">ReplaceRegExp</a><br>
<a href="OptionalTasks/rexec.html">RExec</a><br>
<a href="OptionalTasks/rpm.html">Rpm</a><br>
<a href="OptionalTasks/serverdeploy.html">ServerDeploy</a><br>
<a href="OptionalTasks/setproxy.html">Setproxy</a><br>
<a href="OptionalTasks/schemavalidate.html">SchemaValidate</a><br>
<a href="OptionalTasks/scp.html">Scp</a><br>
<a href="OptionalTasks/script.html">Script</a><br>
<a href="OptionalTasks/scriptdef.html">Scriptdef</a><br>
<a href="OptionalTasks/serverdeploy.html">ServerDeploy</a><br>
<a href="OptionalTasks/setproxy.html">Setproxy</a><br>
<a href="OptionalTasks/sound.html">Sound</a><br>
<a href="OptionalTasks/sos.html">SourceOffSite</a><br>
<a href="OptionalTasks/splash.html">Splash</a><br>


+ 30
- 0
src/etc/testcases/taskdefs/optional/schemavalidate.xml View File

@@ -0,0 +1,30 @@
<project name="validate" default="default" basedir=".">


<property name="doc.xsd" location="xml/doc.xsd"/>
<property name="doc-in-ns.xsd" location="xml/doc-in-ns.xsd"/>
<property name="namespace" value="http://apache.org/ant/doc/" />
<property name="endpiece-ns-no-location.xml"
location="xml/endpiece-ns-no-location.xml"/>

<target name="testNoNamespace">
<schemavalidate
defaultSchemaFile="${doc.xsd}"
file="xml/endpiece-noSchema.xml">
</schemavalidate>
</target>

<target name="testNSMapping">
<schemavalidate
file="${endpiece-ns-no-location.xml}">
<schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
<schema namespace="http://apache.org/ant/2"
url="http://ant.apache.org/" />
</schemavalidate>
</target>

<target name="default" depends="testNoNamespace,testNSMapping" />
</project>

+ 22
- 0
src/etc/testcases/taskdefs/optional/xml/doc-in-ns.xsd View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://apache.org/ant/doc/"
xmlns:tns="http://apache.org/ant/doc/"
elementFormDefault="qualified">
<xs:element name="doc">
<xs:complexType>
<xs:sequence>
<xs:element ref="tns:section"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="section">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="title" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>

+ 7
- 0
src/etc/testcases/taskdefs/optional/xml/endpiece-ns-no-location.xml View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="doc-in-ns.xsd" xmlns="http://apache.org/ant/doc/">
<section title="endpiece">
With a little luck, the network will pick me up.
This is Ripley - last survivor of The Nostromo - signing off.
</section>
</doc>

+ 2
- 4
src/etc/testcases/taskdefs/optional/xml/endpiece.xml View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="doc.xsd"
xmlns="http://Massive/Attack+Mezzanine">
<section title="endpiece">
<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="doc-in-ns.xsd" xmlns="http://apache.org/ant/doc/">
<section title="endpiece">
With a little luck, the network will pick me up.
This is Ripley - last survivor of The Nostromo - signing off.
</section>


+ 13
- 0
src/etc/testcases/taskdefs/optional/xmlvalidate.xml View File

@@ -175,5 +175,18 @@
</xmlvalidate>
</target>

<target name="testSchemaWithXSD">
<xmlvalidate warn="false" lenient="false"
file="xml/endpiece-noSchema.xml">
<attribute name="http://apache.org/xml/features/validation/schema"
value="true"/>
<property
name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
value="${xsd.file}"/>

</xmlvalidate>
</target>
</project>


+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -206,6 +206,7 @@ rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask
scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef
ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm
apt=org.apache.tools.ant.taskdefs.Apt
schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate

# deprecated ant tasks (kept for back compatibility)
starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut


+ 361
- 0
src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java View File

@@ -0,0 +1,361 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.DTDLocation;
import org.apache.tools.ant.util.XmlConstants;
import org.apache.tools.ant.util.JAXPUtils;
import org.xml.sax.XMLReader;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXException;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.io.File;
import java.net.MalformedURLException;


/**
* Validate XML Schema documents.
* This task validates XML schema documents. It requires an XML parser
* that handles the relevant SAx, Xerces or JAXP options.
*
* To resolve remote referencies, Ant may need its proxy set up, using the
* setproxy task.
*
* Hands off most of the work to its parent, {@link XMLValidateTask}
* @since Ant1.7
*/

public class SchemaValidate extends XMLValidateTask {

private List schemaLocations= new ArrayList();

/** full checking of a schema */
private boolean fullChecking=true;

/**
* default URL for nonamespace schemas
*/
private SchemaLocation anonymousSchema;

public static final String ERROR_SAX_1 = "SAX1 parsers are not supported";
public static final String ERROR_NO_XSD_SUPPORT =
"Parser does not support Xerces or JAXP schema features";
public static final String ERROR_TOO_MANY_DEFAULT_SCHEMAS =
"Only one of defaultSchemaFile and defaultSchemaURL allowed";
public static final String ERROR_PARSER_CREATION_FAILURE = "Could not create parser";

/**
* Called by the project to let the task initialize properly. The default
* implementation is a no-op.
*
* @throws BuildException if something goes wrong with the build
*/
public void init() throws BuildException {
super.init();
//validating
setLenient(false);
}

public boolean enableXercesSchemaValidation() {
try {
setFeature(XmlConstants.FEATURE_XSD,true);
//set the schema source for the doc
setNoNamespaceSchemaProperty(
XmlConstants.PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION);
} catch (BuildException e) {
log(e.toString(),Project.MSG_VERBOSE);
return false;
}
return true;
}

private void setNoNamespaceSchemaProperty(String property) {
String anonSchema = getNoNamespaceSchemaURL();
if (anonSchema != null) {
setProperty(property,
anonSchema);
}
}

/**
* JAXP12 schema attributes
* @see <A href="http://java.sun.com/xml/jaxp/change-requests-11.html">
* JAXP 1.2 Approved CHANGES</A>
* @return
*/
public boolean enableJAXP12SchemaValidation() {
try {
//enable XSD
setProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_LANGUAGE,
XmlConstants.URI_XSD);
//set the schema source for the doc
setNoNamespaceSchemaProperty(
XmlConstants.FEATURE_JAXP12_SCHEMA_SOURCE);
} catch (BuildException e) {
log(e.toString(), Project.MSG_VERBOSE);
return false;
}
return true;
}

public void addSchema(SchemaLocation location) {
schemaLocations.add(location);
}

/**
* enable full schema checking. Slower but better.
* @param fullChecking
*/
public void setFullChecking(boolean fullChecking) {
this.fullChecking = fullChecking;
}


/**
* create a schema location to hold the anonymous
* schema
*/
protected void createAnonymousSchema() {
if(anonymousSchema==null) {
anonymousSchema=new SchemaLocation();
}
anonymousSchema.setNamespace("(no namespace)");
}
/**
* identify the URL of the default schema
* @param defaultSchemaURL
*/
public void setNoNamespaceURL(String defaultSchemaURL) {
createAnonymousSchema();
this.anonymousSchema.setUrl(defaultSchemaURL);
}

/**
* identify a file containing the default schema
* @param defaultSchemaFile
*/
public void setNoNamespaceFile(File defaultSchemaFile) {
createAnonymousSchema();
this.anonymousSchema.setFile(defaultSchemaFile);
}

/**
* init the parser : load the parser class, and set features if necessary It
* is only after this that the reader is valid
*
* @throws BuildException if something went wrong
*/
protected void initValidator() {
super.initValidator();
XMLReader xmlReader = getXmlReader();
//validate the parser type
if(isSax1Parser()) {
throw new BuildException(ERROR_SAX_1);
}

//enable schema
//setFeature(XmlConstants.FEATURE_VALIDATION,false);
setFeature(XmlConstants.FEATURE_NAMESPACES,true);
if(!enableXercesSchemaValidation() &&
!enableJAXP12SchemaValidation()) {
//couldnt use the xerces or jaxp calls
throw new BuildException(ERROR_NO_XSD_SUPPORT);
}

//enable schema checking
setFeature(XmlConstants.FEATURE_XSD_FULL_VALIDATION,fullChecking);

//turn off DTDs
setFeatureIfSupported(XmlConstants.FEATURE_DISALLOW_DTD,true);
//schema declarations go in next
addSchemaLocations();
}

/**
* Create a reader if the use of the class did not specify another one.
* The reason to not use {@link JAXPUtils#getXMLReader()} was to
* create our own factory with our own options.
* @return
*/
protected XMLReader createDefaultReader() {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
XMLReader reader = null;
try {
SAXParser saxParser = factory.newSAXParser();
reader = saxParser.getXMLReader();
} catch (ParserConfigurationException e) {
throw new BuildException(ERROR_PARSER_CREATION_FAILURE,e);
} catch (SAXException e) {
throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
}
return reader;
}

/**
* build a string list of all schema locations, then set the relevant
* property.
*/
protected void addSchemaLocations() {
Iterator it = schemaLocations.iterator();
StringBuffer buffer = new StringBuffer();
int count = 0;
while (it.hasNext()) {
if (count > 0) {
buffer.append(' ');
}
SchemaLocation schemaLocation = (SchemaLocation) it.next();
String tuple = schemaLocation.getURIandLocation();
buffer.append(tuple);
count++;
}
if (count > 0) {
setProperty(XmlConstants.PROPERTY_SCHEMA_LOCATION, buffer.toString());
}

}

/**
* get the URL of the no namespace schema
* @return
*/
protected String getNoNamespaceSchemaURL() {
if(anonymousSchema==null) {
return null;
} else {
return anonymousSchema.getSchemaLocationURL();
}
}

/**
* set a feature if it is supported, log at verbose level if
* not
* @param feature
* @param value
*/
protected void setFeatureIfSupported(String feature,boolean value) {
try {
getXmlReader().setFeature(feature, value);
} catch (SAXNotRecognizedException e) {
log("Not recognizied: "+feature,Project.MSG_VERBOSE);
} catch (SAXNotSupportedException e) {
log("Not supported: " + feature, Project.MSG_VERBOSE);
}
}

/**
* representation of a schema location. This is a URI plus either a file or
* a url
*/
public static class SchemaLocation {
private String namespace;
private File file;
private String url;

public static final String ERROR_NO_URI = "No URI";
private static final String ERROR_TWO_LOCATIONS =
"Both URL and File were given for schema ";
public static final String ERROR_NO_FILE = "File not found: ";
public static final String ERROR_NO_URL_REPRESENTATION = "Cannot make a URL of ";
public static final String ERROR_NO_LOCATION = "No file or URL supplied for the schema ";

public SchemaLocation() {
}


public String getNamespace() {
return namespace;
}

public void setNamespace(String namespace) {
this.namespace = namespace;
}

public File getFile() {
return file;
}

public void setFile(File file) {
this.file = file;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getSchemaLocationURL() {
boolean hasFile = file != null;
boolean hasURL = isSet(url);
//error if both are empty, or both are set
if(!hasFile && !hasURL) {
throw new BuildException(
ERROR_NO_LOCATION+namespace);
}
if (hasFile && hasURL) {
throw new BuildException(ERROR_TWO_LOCATIONS + namespace);
}
String schema = url;
if (hasFile) {
if (!file.exists()) {
throw new BuildException(ERROR_NO_FILE + file);
}
try {
schema = file.toURL().toString();
} catch (MalformedURLException e) {
//this is almost implausible, but required handling
throw new BuildException(ERROR_NO_URL_REPRESENTATION + file,e);
}
}
return schema;
}

/**
* validate the fields then create a "uri location" string
*
* @return string of uri and location
* @throws BuildException
*/
public String getURIandLocation() throws BuildException {
if (!isSet(getNamespace())) {
throw new BuildException(ERROR_NO_URI);
}
StringBuffer buffer = new StringBuffer();
buffer.append(namespace);
buffer.append(' ');
buffer.append(getSchemaLocationURL());
return new String(buffer);
}

private boolean isSet(String property) {
return property != null && property.length() != 0;
}
} //SchemaLocation
}

+ 94
- 31
src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java View File

@@ -33,6 +33,7 @@ import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.XMLCatalog;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.JAXPUtils;
import org.apache.tools.ant.util.XmlConstants;

import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
@@ -258,6 +259,19 @@ public class XMLValidateTask extends Task {
protected EntityResolver getEntityResolver() {
return xmlCatalog;
}

/**
* get the XML reader. Non-null only after {@link #initValidator()}.
* If the reader is an instance of {@link ParserAdapter} then
* the parser is a SAX1 parser, and you cannot call
* {@link #setFeature(String, boolean)} or {@link #setProperty(String, String)}
* on it.
* @return the XML reader or null.
*/
protected XMLReader getXmlReader() {
return xmlReader;
}

/**
* execute the task
* @throws BuildException if <code>failonerror</code> is true and an error happens
@@ -304,16 +318,56 @@ public class XMLValidateTask extends Task {
/**
* init the parser :
* load the parser class, and set features if necessary
* It is only after this that the reader is valid
* @throws BuildException if something went wrong
*/
protected void initValidator() {

xmlReader=createXmlReader();

xmlReader.setEntityResolver(getEntityResolver());
xmlReader.setErrorHandler(errorHandler);

if (!isSax1Parser()) {
// turn validation on
if (!lenient) {
setFeature(XmlConstants.FEATURE_VALIDATION, true);
}
// set the feature from the attribute list
for (int i = 0; i < attributeList.size(); i++) {
Attribute feature = (Attribute) attributeList.elementAt(i);
setFeature(feature.getName(), feature.getValue());

}

// Sets properties
for (int i = 0; i < propertyList.size(); i++) {
final Property prop = (Property) propertyList.elementAt(i);
setProperty(prop.getName(), prop.getValue());
}
}
}

/**
* test that returns true if we are using a SAX1 parser.
* @return true when a SAX1 parser is in use
*/
private void initValidator() {
protected boolean isSax1Parser() {
return (xmlReader instanceof ParserAdapter);
}

/**
* create the XML reader.
* This is one by instantiating anything specified by {@link #readerClassName},
* falling back to a default reader if not.
* If the returned reader is an instance of {@link ParserAdapter} then
* we have created and wrapped a SAX1 parser.
* @returns the new XMLReader.
*/
protected XMLReader createXmlReader() {
Object reader = null;
if (readerClassName == null) {
try {
reader = JAXPUtils.getXMLReader();
} catch (BuildException exc) {
reader = JAXPUtils.getParser();
}
reader = createDefaultReaderOrParser();
} else {

Class readerClass = null;
@@ -338,8 +392,9 @@ public class XMLValidateTask extends Task {
}

// then check it implements XMLReader
XMLReader newReader;
if (reader instanceof XMLReader) {
xmlReader = (XMLReader) reader;
newReader = (XMLReader) reader;
log(
"Using SAX2 reader " + reader.getClass().getName(),
Project.MSG_VERBOSE);
@@ -347,7 +402,7 @@ public class XMLValidateTask extends Task {

// see if it is a SAX1 Parser
if (reader instanceof Parser) {
xmlReader = new ParserAdapter((Parser) reader);
newReader = new ParserAdapter((Parser) reader);
log(
"Using SAX1 parser " + reader.getClass().getName(),
Project.MSG_VERBOSE);
@@ -358,36 +413,41 @@ public class XMLValidateTask extends Task {
+ " implements nor SAX1 Parser nor SAX2 XMLReader.");
}
}
return newReader;
}

xmlReader.setEntityResolver(getEntityResolver());
xmlReader.setErrorHandler(errorHandler);

if (!(xmlReader instanceof ParserAdapter)) {
// turn validation on
if (!lenient) {
setFeature("http://xml.org/sax/features/validation", true);
}
// set the feature from the attribute list
for (int i = 0; i < attributeList.size(); i++) {
Attribute feature = (Attribute) attributeList.elementAt(i);
setFeature(feature.getName(), feature.getValue());

}

// Sets properties
for (int i = 0; i < propertyList.size(); i++) {
final Property prop = (Property) propertyList.elementAt(i);
setProperty(prop.getName(), prop.getValue());
}
/**
*
* @return
*/
private Object createDefaultReaderOrParser() {
Object reader;
try {
reader = createDefaultReader();
} catch (BuildException exc) {
reader = JAXPUtils.getParser();
}
return reader;
}

/**
* create a reader if the use of the class did not specify another one.
* If a BuildException is thrown, the caller may revert to an alternate
* reader.
* @return a new reader.
* @throws BuildException if something went wrong
*/
protected XMLReader createDefaultReader() {
return JAXPUtils.getXMLReader();
}

/**
* Set a feature on the parser.
* @param feature the name of the feature to set
* @param value the value of the feature
* @throws BuildException if the feature was not supported
*/
private void setFeature(String feature, boolean value)
protected void setFeature(String feature, boolean value)
throws BuildException {
log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG);
try {
@@ -417,8 +477,9 @@ public class XMLValidateTask extends Task {
* @param name a property name
* @param value a property value.
* @throws BuildException if an error occurs.
* @throws BuildException if the property was not supported
*/
private void setProperty(String name, String value) throws BuildException {
protected void setProperty(String name, String value) throws BuildException {
// Validates property
if (name == null || value == null) {
throw new BuildException("Property name and value must be specified.");
@@ -448,7 +509,7 @@ public class XMLValidateTask extends Task {
/**
* parse the file
*/
private void doValidate(File afile) {
protected void doValidate(File afile) {
try {
log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE);
errorHandler.init(afile);
@@ -655,4 +716,6 @@ public class XMLValidateTask extends Task {

} // Property



}

+ 47
- 0
src/main/org/apache/tools/ant/util/XmlConstants.java View File

@@ -0,0 +1,47 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.util;

/**
* XML Parser constants, all kept in one place for ease of reuse
* @see <a href="http://xml.apache.org/xerces-j/features.html">Xerces features</a>
* @see <a href="http://xml.apache.org/xerces-j/properties.html">Xerces properties</a>
* @see <a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description">SAX.</a>
*/

public class XmlConstants {
public static final String PROPERTY_SCHEMA_LOCATION =
"http://apache.org/xml/properties/schema/external-schemaLocation";
public static final String PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION =
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
public static final String FEATURE_XSD_FULL_VALIDATION =
"http://apache.org/xml/features/validation/schema-full-checking";
public static final String FEATURE_XSD = "http://apache.org/xml/features/validation/schema";

public static final String FEATURE_VALIDATION = "http://xml.org/sax/features/validation";
public static final String FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces";
public static final String FEATURE_JAXP12_SCHEMA_LANGUAGE =
"http://java.sun.com/xml/jaxp/properties/schemaLanguage";
public static final String FEATURE_JAXP12_SCHEMA_SOURCE =
"http://java.sun.com/xml/jaxp/properties/schemaSource";
public static final String URI_XSD =
"http://www.w3.org/2001/XMLSchema";
public static final String FEATURE_EXTERNAL_ENTITIES =
"http://xml.org/sax/features/external-general-entities";
public static final String FEATURE_DISALLOW_DTD =
"http://apache.org/xml/features/disallow-doctype-decl";
}

+ 63
- 0
src/testcases/org/apache/tools/ant/taskdefs/optional/SchemaValidateTest.java View File

@@ -0,0 +1,63 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional;

import org.apache.tools.ant.BuildFileTest;

/**
* Test schema validation
*/

public class SchemaValidateTest extends BuildFileTest {

/**
* where tasks run
*/
private final static String TASKDEFS_DIR =
"src/etc/testcases/taskdefs/optional/";

/**
* Constructor
*
* @param name testname
*/
public SchemaValidateTest(String name) {
super(name);
}

/**
* The JUnit setup method
*/
public void setUp() {
configureProject(TASKDEFS_DIR + "schemavalidate.xml");
}

/**
* test with no namespace
*/
public void testNoNamespace() throws Exception {
executeTarget("testNoNamespace");
}

/**
* add namespace awareness.
*/
public void testNSMapping() throws Exception {
executeTarget("testNSMapping");
}

}

Loading…
Cancel
Save