git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277707 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -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><xmlcatalog></tt></a> elements</li> | |||||
| <li> <tt><schema></tt> elements, that bind a namespace URI to a URL or a | |||||
| local filename. | |||||
| <li><tt><dtd></tt> elements which are used to resolve DTDs and entities.</li> | |||||
| <li><tt><attribute></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><property></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><classpath></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><dtd></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><xmlcatalog></tt></a> | |||||
| element is used to perform entity resolution.</p> | |||||
| <h4>attribute</h4> | |||||
| <p>The <tt><attribute></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><property></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> | |||||
| <xmlvalidate file="toto.xml"/> | |||||
| </pre> | |||||
| Validate toto.xml | |||||
| <pre> | |||||
| <xmlvalidate failonerror="no" lenient="yes" warn="yes" | |||||
| classname="org.apache.xerces.parsers.SAXParser"> | |||||
| classpath="lib/xerces.jar"> | |||||
| <fileset dir="src" includes="style/*.xsl"/> | |||||
| </xmlvalidate> | |||||
| </pre> | |||||
| Validate all .xsl files in src/style, but only warn if there is an error, rather than | |||||
| halt the build. | |||||
| <pre> | |||||
| <xmlvalidate file="struts-config.xml" warn="false"> | |||||
| <dtd publicId="-//Apache Software Foundation//DTD Struts Configuration 1.0//EN" | |||||
| location="struts-config_1_0.dtd"/> | |||||
| </xmlvalidate> | |||||
| </pre> | |||||
| Validate a struts configuration, using a local copy of the DTD. | |||||
| <pre> | |||||
| <xmlvalidate failonerror="no"> | |||||
| <fileset dir="${project.dir}" includes="**/*.xml"/> | |||||
| <xmlcatalog refid="mycatalog"/> | |||||
| </xmlvalidate> | |||||
| </pre> | |||||
| Scan all XML files in the project, using a predefined catalog to map URIs to local files. | |||||
| <pre> | |||||
| <xmlvalidate failonerror="no"> | |||||
| <fileset dir="${project.dir}" includes="**/*.xml"/> | |||||
| <xmlcatalog> | |||||
| <dtd | |||||
| publicId="-//ArielPartners//DTD XML Article V1.0//EN" | |||||
| location="com/arielpartners/knowledgebase/dtd/article.dtd"/> | |||||
| </xmlcatalog> | |||||
| </xmlvalidate> | |||||
| </pre> | |||||
| Scan all XML files in the project, using the catalog defined inline. | |||||
| <pre> | |||||
| <xmlvalidate failonerror="yes" lenient="no" warn="yes"> | |||||
| <fileset dir="xml" includes="**/*.xml"/> | |||||
| <attribute name="http://xml.org/sax/features/validation" value="true"/> | |||||
| <attribute name="http://apache.org/xml/features/validation/schema" value="true"/> | |||||
| <attribute name="http://xml.org/sax/features/namespaces" value="true"/> | |||||
| </xmlvalidate> | |||||
| </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 --> | |||||
| <pathconvert dirsep="/" property="xsd.file"> | |||||
| <path> | |||||
| <pathelement location="xml/doc.xsd"/> | |||||
| </path> | |||||
| </pathconvert> | |||||
| <xmlvalidate file="xml/endpiece-noSchema.xml" lenient="false" | |||||
| failonerror="true" warn="true"> | |||||
| <attribute name="http://apache.org/xml/features/validation/schema" | |||||
| value="true"/> | |||||
| <attribute name="http://xml.org/sax/features/namespaces" value="true"/> | |||||
| <property | |||||
| name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation" | |||||
| value="${xsd.file}"/> | |||||
| </xmlvalidate> | |||||
| </pre> | |||||
| <br> | |||||
| Validate the file xml/endpiece-noSchema.xml against the schema xml/doc.xsd. | |||||
| <br> | |||||
| <hr> | |||||
| <p align="center">Copyright © 2001-2002,2004 The Apache Software Foundation. All rights | |||||
| Reserved.</p> | |||||
| </body> | |||||
| </html> | |||||
| @@ -56,11 +56,12 @@ | |||||
| <a href="OptionalTasks/replaceregexp.html">ReplaceRegExp</a><br> | <a href="OptionalTasks/replaceregexp.html">ReplaceRegExp</a><br> | ||||
| <a href="OptionalTasks/rexec.html">RExec</a><br> | <a href="OptionalTasks/rexec.html">RExec</a><br> | ||||
| <a href="OptionalTasks/rpm.html">Rpm</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/scp.html">Scp</a><br> | ||||
| <a href="OptionalTasks/script.html">Script</a><br> | <a href="OptionalTasks/script.html">Script</a><br> | ||||
| <a href="OptionalTasks/scriptdef.html">Scriptdef</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/sound.html">Sound</a><br> | ||||
| <a href="OptionalTasks/sos.html">SourceOffSite</a><br> | <a href="OptionalTasks/sos.html">SourceOffSite</a><br> | ||||
| <a href="OptionalTasks/splash.html">Splash</a><br> | <a href="OptionalTasks/splash.html">Splash</a><br> | ||||
| @@ -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> | |||||
| @@ -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> | |||||
| @@ -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> | |||||
| @@ -1,8 +1,6 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | <?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. | With a little luck, the network will pick me up. | ||||
| This is Ripley - last survivor of The Nostromo - signing off. | This is Ripley - last survivor of The Nostromo - signing off. | ||||
| </section> | </section> | ||||
| @@ -175,5 +175,18 @@ | |||||
| </xmlvalidate> | </xmlvalidate> | ||||
| </target> | </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> | </project> | ||||
| @@ -206,6 +206,7 @@ rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask | |||||
| scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef | scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef | ||||
| ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm | ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm | ||||
| apt=org.apache.tools.ant.taskdefs.Apt | apt=org.apache.tools.ant.taskdefs.Apt | ||||
| schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate | |||||
| # deprecated ant tasks (kept for back compatibility) | # deprecated ant tasks (kept for back compatibility) | ||||
| starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut | starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut | ||||
| @@ -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 | |||||
| } | |||||
| @@ -33,6 +33,7 @@ import org.apache.tools.ant.types.Reference; | |||||
| import org.apache.tools.ant.types.XMLCatalog; | import org.apache.tools.ant.types.XMLCatalog; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.JAXPUtils; | import org.apache.tools.ant.util.JAXPUtils; | ||||
| import org.apache.tools.ant.util.XmlConstants; | |||||
| import org.xml.sax.EntityResolver; | import org.xml.sax.EntityResolver; | ||||
| import org.xml.sax.ErrorHandler; | import org.xml.sax.ErrorHandler; | ||||
| @@ -258,6 +259,19 @@ public class XMLValidateTask extends Task { | |||||
| protected EntityResolver getEntityResolver() { | protected EntityResolver getEntityResolver() { | ||||
| return xmlCatalog; | 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 | * execute the task | ||||
| * @throws BuildException if <code>failonerror</code> is true and an error happens | * @throws BuildException if <code>failonerror</code> is true and an error happens | ||||
| @@ -304,16 +318,56 @@ public class XMLValidateTask extends Task { | |||||
| /** | /** | ||||
| * init the parser : | * init the parser : | ||||
| * load the parser class, and set features if necessary | * 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; | Object reader = null; | ||||
| if (readerClassName == null) { | if (readerClassName == null) { | ||||
| try { | |||||
| reader = JAXPUtils.getXMLReader(); | |||||
| } catch (BuildException exc) { | |||||
| reader = JAXPUtils.getParser(); | |||||
| } | |||||
| reader = createDefaultReaderOrParser(); | |||||
| } else { | } else { | ||||
| Class readerClass = null; | Class readerClass = null; | ||||
| @@ -338,8 +392,9 @@ public class XMLValidateTask extends Task { | |||||
| } | } | ||||
| // then check it implements XMLReader | // then check it implements XMLReader | ||||
| XMLReader newReader; | |||||
| if (reader instanceof XMLReader) { | if (reader instanceof XMLReader) { | ||||
| xmlReader = (XMLReader) reader; | |||||
| newReader = (XMLReader) reader; | |||||
| log( | log( | ||||
| "Using SAX2 reader " + reader.getClass().getName(), | "Using SAX2 reader " + reader.getClass().getName(), | ||||
| Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
| @@ -347,7 +402,7 @@ public class XMLValidateTask extends Task { | |||||
| // see if it is a SAX1 Parser | // see if it is a SAX1 Parser | ||||
| if (reader instanceof Parser) { | if (reader instanceof Parser) { | ||||
| xmlReader = new ParserAdapter((Parser) reader); | |||||
| newReader = new ParserAdapter((Parser) reader); | |||||
| log( | log( | ||||
| "Using SAX1 parser " + reader.getClass().getName(), | "Using SAX1 parser " + reader.getClass().getName(), | ||||
| Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
| @@ -358,36 +413,41 @@ public class XMLValidateTask extends Task { | |||||
| + " implements nor SAX1 Parser nor SAX2 XMLReader."); | + " 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. | * Set a feature on the parser. | ||||
| * @param feature the name of the feature to set | * @param feature the name of the feature to set | ||||
| * @param value the value of the feature | * @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 { | throws BuildException { | ||||
| log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG); | log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG); | ||||
| try { | try { | ||||
| @@ -417,8 +477,9 @@ public class XMLValidateTask extends Task { | |||||
| * @param name a property name | * @param name a property name | ||||
| * @param value a property value. | * @param value a property value. | ||||
| * @throws BuildException if an error occurs. | * @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 | // Validates property | ||||
| if (name == null || value == null) { | if (name == null || value == null) { | ||||
| throw new BuildException("Property name and value must be specified."); | throw new BuildException("Property name and value must be specified."); | ||||
| @@ -448,7 +509,7 @@ public class XMLValidateTask extends Task { | |||||
| /** | /** | ||||
| * parse the file | * parse the file | ||||
| */ | */ | ||||
| private void doValidate(File afile) { | |||||
| protected void doValidate(File afile) { | |||||
| try { | try { | ||||
| log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE); | log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE); | ||||
| errorHandler.init(afile); | errorHandler.init(afile); | ||||
| @@ -655,4 +716,6 @@ public class XMLValidateTask extends Task { | |||||
| } // Property | } // Property | ||||
| } | } | ||||
| @@ -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"; | |||||
| } | |||||
| @@ -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"); | |||||
| } | |||||
| } | |||||