You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by eh...@apache.org on 2002/05/24 17:47:57 UTC

cvs commit: jakarta-ant/src/testcases/org/apache/tools/ant/types XMLCatalogTest.java

ehatcher    02/05/24 08:47:57

  Modified:    src/main/org/apache/tools/ant/types Tag: ANT_15_BRANCH
                        XMLCatalog.java
               docs/manual/CoreTasks Tag: ANT_15_BRANCH style.html
               docs/manual/OptionalTasks Tag: ANT_15_BRANCH
                        xmlvalidate.html
               src/testcases/org/apache/tools/ant/taskdefs/optional Tag:
                        ANT_15_BRANCH XmlValidateTest.java
               src/etc/testcases/taskdefs/optional Tag: ANT_15_BRANCH
                        xmlvalidate.xml
               src/main/org/apache/tools/ant/taskdefs Tag: ANT_15_BRANCH
                        XSLTProcess.java
               src/main/org/apache/tools/ant/taskdefs/optional Tag:
                        ANT_15_BRANCH TraXLiaison.java
               docs/manual/CoreTypes Tag: ANT_15_BRANCH xmlcatalog.html
  Added:       src/testcases/org/apache/tools/ant/types Tag: ANT_15_BRANCH
                        XMLCatalogTest.java
  Log:
  patch submitted by Craeg K Strong. Mostly doc patches, but also added capability to set a URIResolver as well as an EntityResolver.
  
  Note: commented out some asserts that were failing for me in XMLCatalogTest - looks like minor path issues.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.9.2.2   +371 -94   jakarta-ant/src/main/org/apache/tools/ant/types/XMLCatalog.java
  
  Index: XMLCatalog.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/types/XMLCatalog.java,v
  retrieving revision 1.9.2.1
  retrieving revision 1.9.2.2
  diff -u -r1.9.2.1 -r1.9.2.2
  --- XMLCatalog.java	20 May 2002 18:44:38 -0000	1.9.2.1
  +++ XMLCatalog.java	24 May 2002 15:47:56 -0000	1.9.2.2
  @@ -58,17 +58,30 @@
   import java.io.FileInputStream;
   import java.io.InputStream;
   import java.io.IOException;
  +import java.io.FileNotFoundException;
   import java.net.URL;
  +import java.net.MalformedURLException;
   import java.util.Enumeration;
  +import java.util.Stack;
   import java.util.Vector;
  +import javax.xml.transform.Source;
  +import javax.xml.transform.TransformerException;
  +import javax.xml.transform.URIResolver;
  +import javax.xml.transform.sax.SAXSource;
  +import javax.xml.parsers.SAXParserFactory;
  +import javax.xml.parsers.ParserConfigurationException;
  +
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.AntClassLoader;
  +import org.apache.tools.ant.util.FileUtils;
  +
   import org.xml.sax.EntityResolver;
   import org.xml.sax.InputSource;
   import org.xml.sax.SAXException;
  -import org.apache.tools.ant.util.LoaderUtils;
  -import org.apache.tools.ant.util.FileUtils;
  +import org.xml.sax.XMLReader;
  +
  +
   
   /**
    * This data type provides a catalog of DTD locations.
  @@ -83,7 +96,7 @@
    * </code>
    * <p>
    * The object implemention <code>sometask</code> must provide a method called
  - * <code>createXMLCatalog</code> which returns an instance of 
  + * <code>createXMLCatalog</code> which returns an instance of
    * <code>XMLCatalog</code>. Nested DTD and entity definitions are handled by
    * the XMLCatalog object and must be labeled <code>dtd</code> and
    * <code>entity</code> respectively.</p>
  @@ -93,21 +106,21 @@
    *
    * @author dIon Gillard
    * @author Erik Hatcher
  - * @version $Id: XMLCatalog.java,v 1.9.2.1 2002/05/20 18:44:38 ehatcher Exp $
  + * @version $Id: XMLCatalog.java,v 1.9.2.2 2002/05/24 15:47:56 ehatcher Exp $
    */
   public class XMLCatalog extends DataType implements Cloneable, EntityResolver {
       /** File utilities instance */
       private FileUtils fileUtils = FileUtils.newFileUtils();
  -    
  +
       //-- Fields ----------------------------------------------------------------
  -    
  +
       /** holds dtd/entity objects until needed */
       private Vector elements = new Vector();
   
       private Path classpath;
   
       //-- Methods ---------------------------------------------------------------
  -    
  +
       /**
        * @return the elements of the catalog - DTDLocation objects
        */
  @@ -116,6 +129,8 @@
       }
   
       /**
  +     * Returns the classpath in which to attempt to resolve resources.
  +     *
        * @return the classpath
        */
       private Path getClasspath() {
  @@ -123,25 +138,22 @@
       }
   
       /**
  -     * Set the list of DTDLocation object sin the catalog
  +     * Set the list of DTDLocation objects in the catalog.  Not
  +     * allowed if this catalog is itself a reference to another
  +     * catalog -- that is, a catalog cannot both refer to another
  +     * <em>and</em> contain elements or other attributes.
        *
        * @param aVector the new list of DTD Locations to use in the catalog.
        */
       private void setElements(Vector aVector) {
           elements = aVector;
       }
  -    
  -    /**
  -     * Add a DTD Location to the catalog
  -     *
  -     * @param aDTD the DTDLocation instance to be aded to the catalog
  -     */
  -    private void addElement(DTDLocation aDTD) {
  -        getElements().addElement(aDTD);
  -    }
   
       /**
  -     * Allows nested classpath elements
  +     * Allows nested classpath elements. Not allowed if this catalog
  +     * is itself a reference to another catalog -- that is, a catalog
  +     * cannot both refer to another <em>and</em> contain elements or
  +     * other attributes.
        */
       public Path createClasspath() {
           if (isReference()) {
  @@ -150,11 +162,15 @@
           if (this.classpath == null) {
               this.classpath = new Path(getProject());
           }
  +        checked = false;
           return this.classpath.createPath();
       }
   
       /**
  -     * Allows simple classpath string
  +     * Allows simple classpath string.  Not allowed if this catalog is
  +     * itself a reference to another catalog -- that is, a catalog
  +     * cannot both refer to another <em>and</em> contain elements or
  +     * other attributes.
        */
       public void setClasspath(Path classpath) {
           if (isReference()) {
  @@ -165,23 +181,32 @@
           } else {
               this.classpath.append(classpath);
           }
  +        checked = false;
       }
   
       /**
  -     * Allows classpath reference
  +     * Allows classpath reference.  Not allowed if this catalog is
  +     * itself a reference to another catalog -- that is, a catalog
  +     * cannot both refer to another <em>and</em> contain elements or
  +     * other attributes.
        */
       public void setClasspathRef(Reference r) {
           if (isReference()) {
               throw tooManyAttributes();
           }
           createClasspath().setRefid(r);
  +        checked = false;
       }
   
       /**
  -     * Creates the nested <code>&lt;dtd&gt;</code> element.
  +     * Creates the nested <code>&lt;dtd&gt;</code> element.  Not
  +     * allowed if this catalog is itself a reference to another
  +     * catalog -- that is, a catalog cannot both refer to another
  +     * <em>and</em> contain elements or other attributes.
        *
  -     * @param dtd the infromation about the DTD to be added to the catalog
  -     * @exception BuildException if this is a reference and no nested 
  +     * @param dtd the information about the PUBLIC resource mapping to
  +     *            be added to the catalog
  +     * @exception BuildException if this is a reference and no nested
        *       elements are allowed.
        */
       public void addDTD(DTDLocation dtd) throws BuildException {
  @@ -190,13 +215,18 @@
           }
   
           getElements().addElement(dtd);
  +        checked = false;
       }
  -    
  +
       /**
  -     * Creates the nested <code>&lt;entity&gt;</code> element
  +     * Creates the nested <code>&lt;entity&gt;</code> element.    Not
  +     * allowed if this catalog is itself a reference to another
  +     * catalog -- that is, a catalog cannot both refer to another
  +     * <em>and</em> contain elements or other attributes.
        *
  -     * @param dtd the infromation about the DTD to be added to the catalog
  -     * @exception BuildException if this is a reference and no nested 
  +     * @param dtd the information about the URI resource mapping to be
  +     *       added to the catalog
  +     * @exception BuildException if this is a reference and no nested
        *       elements are allowed.
        */
       public void addEntity(DTDLocation dtd) throws BuildException {
  @@ -204,7 +234,10 @@
       }
   
       /**
  -     * Loads a nested XMLCatalog into our definition
  +     * Loads a nested <code>&lt;xmlcatalog&gt;</code> into our
  +     * definition.  Not allowed if this catalog is itself a reference
  +     * to another catalog -- that is, a catalog cannot both refer to
  +     * another <em>and</em> contain elements or other attributes.
        *
        * @param catalog Nested XMLCatalog
        */
  @@ -224,15 +257,19 @@
           // Append the classpath of the nested catalog
           Path nestedClasspath = catalog.getClasspath();
           createClasspath().append(nestedClasspath);
  +        checked = false;
       }
   
       /**
  -     * Makes this instance in effect a reference to another XCatalog instance.
  +     * Makes this instance in effect a reference to another XMLCatalog
  +     * instance.
        *
  -     * <p>You must not set another attribute or nest elements inside
  -     * this element if you make it a reference.</p>
  +     * <p>You must not set another attribute or nest elements inside *
  +     * this element if you make it a reference.  That is, a catalog
  +     * cannot both refer to another <em>and</em> contain elements or
  +     * attributes.</p>
        *
  -     * @param r the reference to which this catalogi instance is associated
  +     * @param r the reference to which this catalog instance is associated
        * @exception BuildException if this instance already has been configured.
        */
       public void setRefid(Reference r) throws BuildException {
  @@ -241,7 +278,7 @@
           }
           // change this to get the objects from the other reference
           Object o = r.getReferencedObject(getProject());
  -        // we only support references to other XCatalogs
  +        // we only support references to other XMLCatalogs
           if (o instanceof XMLCatalog) {
               // set all elements from referenced catalog to this one
               XMLCatalog catalog = (XMLCatalog) o;
  @@ -250,81 +287,81 @@
               String msg = r.getRefId() + " does not refer to an XMLCatalog";
               throw new BuildException(msg);
           }
  -
           super.setRefid(r);
       }
   
       /**
  +     * Implements the EntityResolver.resolveEntity() interface method.
  +     *
        * @see org.xml.sax.EntityResolver#resolveEntity
        */
       public InputSource resolveEntity(String publicId, String systemId)
           throws SAXException, IOException {
  -        InputSource source = null;
  -        DTDLocation matchingDTD = findMatchingDTD(publicId);
  -        if (matchingDTD != null) {
  -            // check if publicId is mapped to a file
  -            log("Matching DTD found for publicId: '" + publicId +
  -                "' location: '" + matchingDTD.getLocation() + "'",
  -                Project.MSG_DEBUG);
  -            File dtdFile = project.resolveFile(matchingDTD.getLocation());
  -            if (dtdFile.exists() && dtdFile.canRead()) {
  -                source = new InputSource(new FileInputStream(dtdFile));
  -                URL dtdFileURL = fileUtils.getFileURL(dtdFile);
  -                source.setSystemId(dtdFileURL.toExternalForm());
  -                log("matched a readable file", Project.MSG_DEBUG);
  -            } else {
  -                // check if publicId is a resource
  -
  -                AntClassLoader loader = null;
  -                if (classpath != null) {
  -                    loader = new AntClassLoader(project, classpath);
  -                } else {
  -                    loader = new AntClassLoader(project, Path.systemClasspath);
  -                }
   
  -                InputStream is
  -                    = loader.getResourceAsStream(matchingDTD.getLocation());
  -                if (is != null) {
  -                    source = new InputSource(is);
  -                    source.setSystemId(loader.getResource(
  -                        matchingDTD.getLocation()).toExternalForm());
  -                    log("matched a resource", Project.MSG_DEBUG);
  -                } else {
  -                    // check if it's a URL
  -                    try {
  -                        URL dtdUrl = new URL(matchingDTD.getLocation());
  -                        InputStream dtdIs = dtdUrl.openStream();
  -                        if (dtdIs != null) {
  -                            source = new InputSource(dtdIs);
  -                            source.setSystemId(dtdUrl.toExternalForm());
  -                            log("matched as a URL", Project.MSG_DEBUG);
  -                        } else {
  -                            log("No match, parser will use: '" + systemId + "'",
  -                                Project.MSG_DEBUG);
  -                        }
  -                    } catch (IOException ioe) {
  -                        //ignore
  -                    }
  -                }
  -            }
  -        } else {
  -            log("No match, parser will use: '" + systemId + "'",
  -                Project.MSG_DEBUG);
  +       if (!checked) {
  +          // make sure we don't have a circular reference here
  +          Stack stk = new Stack();
  +          stk.push(this);
  +          dieOnCircularReference(stk, getProject());
  +       }
  +
  +        log("resolveEntity: '" + publicId + "': '" + systemId + "'",
  +            Project.MSG_DEBUG);
  +
  +        InputSource inputSource = resolveEntityImpl(publicId, systemId);
  +
  +        if (inputSource == null) {
  +            log("No matching catalog entry found, parser will use: '" +
  +                systemId + "'", Project.MSG_DEBUG);
           }
  -        // else let the parser handle it as a URI as we don't know what to
  -        // do with it
  +
  +        return inputSource;
  +    }
  +
  +    /**
  +     * Implements the URIResolver.resolve() interface method.
  +     *
  +     * @see javax.xml.transform.URIResolver#resolve
  +     */
  +    public Source resolve(String href, String base)
  +        throws TransformerException {
  +
  +       if (!checked) {
  +          // make sure we don't have a circular reference here
  +          Stack stk = new Stack();
  +          stk.push(this);
  +          dieOnCircularReference(stk, getProject());
  +       }
  +
  +        SAXSource source = null;
  +        InputSource inputSource = null;
  +
  +        String uri = removeFragment(href);
  +
  +        log("resolve: '" + uri + "' with base: '" + base + "'", Project.MSG_DEBUG);
  +
  +        source = resolveImpl(uri, base);
  +
  +        if (source == null) {
  +            log("No matching catalog entry found, parser will use: '" +
  +                href + "'", Project.MSG_DEBUG);
  +        }
  +        else {
  +            setEntityResolver(source);
  +        }
  +
           return source;
       }
  -    
  +
       /**
        * Find a DTDLocation instance for the given publicId.
        *
  -     * @param publicId the publicId of the DTD for which local information is 
  -     *        required
  -     * @return a DTDLocation instance with information on the local location 
  -     *         of the DTD or null if no such information is available
  +     * @param publicId the publicId of the Resource for which local information
  +     *        is required
  +     * @return a DTDLocation instance with information on the local location
  +     *         of the Resource or null if no such information is available
        */
  -    private DTDLocation findMatchingDTD(String publicId) {
  +    private DTDLocation findMatchingEntry(String publicId) {
           Enumeration elements = getElements().elements();
           DTDLocation element = null;
           while (elements.hasMoreElements()) {
  @@ -335,6 +372,246 @@
           }
           return null;
       }
  -      
  -}
   
  +    /**
  +     * <p>This is called from the URIResolver to set an EntityResolver
  +     * on the SAX parser to be used for new XML documents that are
  +     * encountered as a result of the document() function, xsl:import,
  +     * or xsl:include.  This is done because the XSLT processor calls
  +     * out to the SAXParserFactory itself to create a new SAXParser to
  +     * parse the new document.  The new parser does not automatically
  +     * inherit the EntityResolver of the original (although arguably
  +     * it should).  See below:</p>
  +     *
  +     * <tt>"If an application wants to set the ErrorHandler or
  +     * EntityResolver for an XMLReader used during a transformation,
  +     * it should use a URIResolver to return the SAXSource which
  +     * provides (with getXMLReader) a reference to the XMLReader"</tt>
  +     *
  +     * <p>...quoted from page 118 of the Java API for XML
  +     * Processing 1.1 specification</p>
  +     *
  +     */
  +    private void setEntityResolver(SAXSource source) throws TransformerException {
  +
  +        XMLReader reader = source.getXMLReader();
  +        if (reader == null) {
  +            SAXParserFactory spFactory = SAXParserFactory.newInstance();
  +            spFactory.setNamespaceAware(true);
  +            try {
  +                reader = spFactory.newSAXParser().getXMLReader();
  +            }
  +            catch (ParserConfigurationException ex) {
  +                throw new TransformerException(ex);
  +            }
  +            catch (SAXException ex) {
  +                throw new TransformerException(ex);
  +            }
  +        }
  +        reader.setEntityResolver(this);
  +        source.setXMLReader(reader);
  +    }
  +
  +    /**
  +     * Utility method to remove trailing fragment from a URI.
  +     * For example,
  +     * <code>http://java.sun.com/index.html#chapter1</code>
  +     * would return <code>http://java.sun.com/index.html</code>.
  +     *
  +     * @param uri The URI to process.  It may or may not contain a
  +     *            fragment.
  +     * @return The URI sans fragment.
  +     */
  +    private String removeFragment(String uri) {
  +        String result = uri;
  +        String fragment = null;
  +        int hashPos = uri.indexOf("#");
  +        if (hashPos >= 0) {
  +            result = uri.substring(0, hashPos);
  +            fragment = uri.substring(hashPos+1);
  +        }
  +        return result;
  +    }
  +
  +    /**
  +     * Utility method to lookup a DTDLocation in the filesystem.
  +     *
  +     * @return An InputSource for reading the file, or <code>null</code>
  +     *     if the file does not exist or is not readable.
  +     */
  +    private InputSource filesystemLookup(DTDLocation matchingEntry) {
  +
  +        String uri = matchingEntry.getLocation();
  +        File basedir = null;
  +
  +        //
  +        // The DTDLocation may specify a relative path for its
  +        // location attribute.  This is resolved using the appropriate
  +        // base.
  +        //
  +        File resFile = project.resolveFile(uri);
  +        InputSource source = null;
  +
  +        if (resFile.exists() && resFile.canRead()) {
  +            try {
  +                source = new InputSource(new FileInputStream(resFile));
  +                URL resFileURL = fileUtils.getFileURL(resFile);
  +                String sysid = resFileURL.toExternalForm();
  +                source.setSystemId(sysid);
  +                log("catalog entry matched a readable file: '" +
  +                    sysid + "'", Project.MSG_DEBUG);
  +            } catch(FileNotFoundException ex) {
  +                // ignore
  +            } catch(MalformedURLException ex) {
  +                // ignore
  +            } catch(IOException ex) {
  +                // ignore
  +            }
  +        }
  +
  +        return source;
  +    }
  +
  +    /**
  +     * Utility method to lookup a DTDLocation in the classpath.
  +     *
  +     * @return An InputSource for reading the resource, or <code>null</code>
  +     *    if the resource does not exist in the classpath or is not readable.
  +     */
  +    private InputSource classpathLookup(DTDLocation matchingEntry) {
  +
  +        InputSource source = null;
  +
  +        AntClassLoader loader = null;
  +        if (classpath != null) {
  +            loader = new AntClassLoader(project, classpath);
  +        } else {
  +            loader = new AntClassLoader(project, Path.systemClasspath);
  +        }
  +
  +        //
  +        // for classpath lookup we ignore the base directory
  +        //
  +        InputStream is
  +            = loader.getResourceAsStream(matchingEntry.getLocation());
  +
  +        if (is != null) {
  +            source = new InputSource(is);
  +            URL entryURL = loader.getResource(matchingEntry.getLocation());
  +            String sysid = entryURL.toExternalForm();
  +            source.setSystemId(sysid);
  +            log("catalog entry matched a resource in the classpath: '" +
  +                sysid + "'", Project.MSG_DEBUG);
  +        }
  +
  +        return source;
  +    }
  +
  +    /**
  +     * Utility method to lookup a DTDLocation in URL-space.
  +     *
  +     * @return An InputSource for reading the resource, or <code>null</code>
  +     *    if the resource does not identify a valid URL or is not readable.
  +     */
  +    private InputSource urlLookup(String uri, String base) {
  +
  +        InputSource source = null;
  +        URL url = null;
  +
  +        try {
  +            if (base == null) {
  +                url = new URL(uri);
  +            }
  +            else {
  +                URL baseURL = new URL(base);
  +                url = (uri.length() == 0 ? baseURL : new URL(baseURL, uri));
  +            }
  +        }
  +        catch (MalformedURLException ex) {
  +            // ignore
  +        }
  +
  +        if (url != null) {
  +            try {
  +                InputStream is = url.openStream();
  +                if (is != null) {
  +                    source = new InputSource(is);
  +                    String sysid = url.toExternalForm();
  +                    source.setSystemId(sysid);
  +                    log("catalog entry matched as a URL: '" +
  +                        sysid + "'", Project.MSG_DEBUG);
  +                }
  +            } catch(IOException ex) {
  +                // ignore
  +            }
  +        }
  +
  +        return source;
  +
  +    }
  +
  +    /**
  +     * Implements the guts of the resolveEntity() lookup strategy.
  +     */
  +    private InputSource resolveEntityImpl(String publicId,
  +                                          String systemId) {
  +
  +        InputSource result = null;
  +
  +        DTDLocation matchingEntry = findMatchingEntry(publicId);
  +
  +        if (matchingEntry != null) {
  +
  +            log("Matching catalog entry found for publicId: '" +
  +                matchingEntry.getPublicId() + "' location: '" +
  +                matchingEntry.getLocation() + "'",
  +                Project.MSG_DEBUG);
  +
  +            result = filesystemLookup(matchingEntry);
  +
  +            if (result == null) {
  +                result = classpathLookup(matchingEntry);
  +            }
  +
  +            if (result == null) {
  +                result = urlLookup(matchingEntry.getLocation(), null);
  +            }
  +        }
  +        return result;
  +    }
  +
  +    /**
  +     * Implements the guts of the resolve() lookup strategy.
  +     */
  +    private SAXSource resolveImpl(String href, String base)
  +        throws TransformerException {
  +
  +        SAXSource result = null;
  +        InputSource source = null;
  +
  +        DTDLocation matchingEntry = findMatchingEntry(href);
  +
  +        if (matchingEntry != null) {
  +
  +            log("Matching catalog entry found for uri: '" +
  +                matchingEntry.getPublicId() + "' location: '" +
  +                matchingEntry.getLocation() + "'",
  +                Project.MSG_DEBUG);
  +
  +            source = filesystemLookup(matchingEntry);
  +
  +            if (source == null) {
  +                source = classpathLookup(matchingEntry);
  +            }
  +
  +            if (source == null) {
  +                source = urlLookup(matchingEntry.getLocation(), base);
  +            }
  +
  +            if (source != null) {
  +                result = new SAXSource(source);
  +            }
  +        }
  +        return result;
  +    }
  +}
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.18.2.2  +21 -2     jakarta-ant/docs/manual/CoreTasks/style.html
  
  Index: style.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/CoreTasks/style.html,v
  retrieving revision 1.18.2.1
  retrieving revision 1.18.2.2
  diff -u -r1.18.2.1 -r1.18.2.2
  --- style.html	3 May 2002 09:40:29 -0000	1.18.2.1
  +++ style.html	24 May 2002 15:47:57 -0000	1.18.2.2
  @@ -27,8 +27,10 @@
     attributes of <code>&lt;fileset&gt;</code> (<code>dir</code> becomes <code>basedir</code>) 
     as well as the nested <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> 
     and <code>&lt;patternset&gt;</code> elements.</p>
  -<p>Style supports the use of a &lt;param&gt; element which is used to pass values 
  +<p>This task supports the use of a nested &lt;param&gt; element which is used to pass values 
     to an &lt;xsl:param&gt; declaration.</p>
  +<p>This task supports the use of a nested <a href="../CoreTypes/xmlcatalog.html">xmlcatalog</a> 
  +element which is used to perform Entity and URI resolution</p>
   <p><i>&lt;style&gt; and &lt;xslt&gt; refer to the same Ant task and can be used interchangeably.</i></p>
   <p>If you want to use Xalan-J 1 or XSL:P, you also need Ant's optional.jar</p>
   <h3>Parameters</h3>
  @@ -161,6 +163,9 @@
   <p>The classpath to load the processor from can be specified via a
   nested <code>&lt;classpath&gt;</code>, as well - that is, a 
   <a href="../using.html#path">path</a>-like structure.</p>
  +<h4>xmlcatalog</h4>
  +<p>The <a href="../CoreTypes/xmlcatalog.html">xmlcatalog</a> 
  +element is used to perform Entity and URI resolution.</p>
   <h4>param</h4>
   <p>Param is used to pass a parameter to the XSL stylesheet.</p>
   <h4>Parameters</h4>
  @@ -187,8 +192,22 @@
     <pre>
   &lt;style basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
          extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;/&gt;</pre>
  -  <h4>Using XSL parameters</h4>
  +  <h4>Using an xmlcatalog</h4>
     <pre>&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
  +      extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&gt;
  +  &lt;xmlcatalog refid=&quot;mycatalog&quot;/&gt;
  +&lt;/xslt&gt;
  +
  +&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
  +   extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&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;/xslt&gt;</pre>
  +  <h4>Using XSL parameters</h4>
  +<pre>&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
         extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&gt;
     &lt;param name=&quot;date&quot; expression=&quot;07-01-2000&quot;/&gt;
   &lt;/xslt&gt;</pre>
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.4.2.1   +21 -0     jakarta-ant/docs/manual/OptionalTasks/xmlvalidate.html
  
  Index: xmlvalidate.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/OptionalTasks/xmlvalidate.html,v
  retrieving revision 1.4
  retrieving revision 1.4.2.1
  diff -u -r1.4 -r1.4.2.1
  --- xmlvalidate.html	22 Apr 2002 08:56:13 -0000	1.4
  +++ xmlvalidate.html	24 May 2002 15:47:57 -0000	1.4.2.1
  @@ -14,6 +14,10 @@
   (probably the one that is used by Ant itself), but one can specify any
   SAX1/2 parser if needed.</p>
   
  +<p>This task supports the use of nested <a
  +href="../CoreTypes/xmlcatalog.html">xmlcatalog</a> elements and/or nested 
  +&lt;dtd&gt; elements which are used to resolve DTDs and entities.</p>
  +
   <h3>Parameters</h3>
   <table border="1" cellpadding="2" cellspacing="0">
     <tr>
  @@ -77,6 +81,9 @@
       <td align="center" valign="top">Yes</td>
     </tr>
   </table>
  +<h4>xmlcatalog</h4>
  +<p>The <a href="../CoreTypes/xmlcatalog.html">xmlcatalog</a> 
  +element is used to perform Entity resolution.</p>
   
   
   <h3>Examples</h3>
  @@ -92,6 +99,20 @@
   &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;
  +
  +&lt;xmlvalidate failonerror="no"&gt;
  +  &lt;fileset dir="${project.dir}" includes="**/*.xml"/&gt;
  +  &lt;xmlcatalog refid="mycatalog"/&gt;
  +&lt;/xmlvalidate&gt;
  +
  +&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></blockquote>
   <hr>
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.2.2.1   +7 -1      jakarta-ant/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java
  
  Index: XmlValidateTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/testcases/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java,v
  retrieving revision 1.2
  retrieving revision 1.2.2.1
  diff -u -r1.2 -r1.2.2.1
  --- XmlValidateTest.java	20 Apr 2002 16:15:11 -0000	1.2
  +++ XmlValidateTest.java	24 May 2002 15:47:57 -0000	1.2.2.1
  @@ -118,5 +118,11 @@
       public void testXmlCatalog() {
           executeTarget("xmlcatalog");
       }
  -}
   
  +    /**
  +     * Test nested xmlcatalog definitions
  +     */
  +    public void testXmlCatalogNested() {
  +        executeTarget("xmlcatalognested");
  +    }
  +}
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.2.2.1   +14 -0     jakarta-ant/src/etc/testcases/taskdefs/optional/xmlvalidate.xml
  
  Index: xmlvalidate.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/etc/testcases/taskdefs/optional/xmlvalidate.xml,v
  retrieving revision 1.2
  retrieving revision 1.2.2.1
  diff -u -r1.2 -r1.2.2.1
  --- xmlvalidate.xml	20 Apr 2002 16:15:10 -0000	1.2
  +++ xmlvalidate.xml	24 May 2002 15:47:57 -0000	1.2.2.1
  @@ -24,5 +24,19 @@
         </xmlcatalog>
       </xmlvalidate>
     </target>
  +
  +  <target name="xmlcatalognested">
  +    <xmlvalidate warn="false">
  +      <fileset dir="xml" includes="**/about.xml"/>
  +      <xmlcatalog classpath="xml">
  +	 <entity publicID = "bogusImage"
  +                 location = "/i/dont/exist.jpg"/>
  +        <xmlcatalog>
  +          <dtd publicID="-//stevo//DTD doc 1.0//EN"
  +               location="doc.dtd"/>
  +        </xmlcatalog>
  +      </xmlcatalog>
  +    </xmlvalidate>
  +  </target>
     
   </project>
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.43.2.1  +12 -6     jakarta-ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
  
  Index: XSLTProcess.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java,v
  retrieving revision 1.43
  retrieving revision 1.43.2.1
  diff -u -r1.43 -r1.43.2.1
  --- XSLTProcess.java	20 Apr 2002 16:11:34 -0000	1.43
  +++ XSLTProcess.java	24 May 2002 15:47:57 -0000	1.43.2.1
  @@ -67,12 +67,13 @@
   import org.apache.tools.ant.util.FileUtils;
   import org.apache.tools.ant.types.XMLCatalog;
   import org.xml.sax.EntityResolver;
  +import javax.xml.transform.URIResolver;
   
   /**
    * A Task to process via XSLT a set of XML documents. This is
    * useful for building views of XML based documentation.
    *
  - * @version $Revision: 1.43 $ 
  + * @version $Revision: 1.43.2.1 $ 
    *
    * @author <a href="mailto:kvisco@exoffice.com">Keith Visco</a>
    * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a>
  @@ -662,14 +663,19 @@
                   liaison.addParam(p.getName(), p.getExpression());
               }
               // if liaison is a TraxLiason, use XMLCatalog as the entity
  -            // resolver
  +            // resolver and URI resolver
               if (liaison.getClass().getName().equals(TRAX_LIAISON_CLASS) &&
                   xmlCatalog != null) {
  -                log("Configuring TraxLiaison and calling entity resolver",
  -                    Project.MSG_DEBUG);
  +                log("Configuring TraxLiaison: setting entity resolver " +
  +                    "and setting URI resolver", Project.MSG_DEBUG);
                   Method resolver = liaison.getClass()
  -                                    .getDeclaredMethod("setEntityResolver", 
  -                                        new Class[] {EntityResolver.class});
  +                    .getDeclaredMethod("setEntityResolver", 
  +                                       new Class[] {EntityResolver.class});
  +                resolver.invoke(liaison, new Object[] {xmlCatalog});
  +
  +                resolver = liaison.getClass()
  +                    .getDeclaredMethod("setURIResolver", 
  +                                       new Class[] {URIResolver.class});
                   resolver.invoke(liaison, new Object[] {xmlCatalog});
               }
           } catch (Exception ex) {
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.17.2.1  +17 -4     jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
  
  Index: TraXLiaison.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java,v
  retrieving revision 1.17
  retrieving revision 1.17.2.1
  diff -u -r1.17 -r1.17.2.1
  --- TraXLiaison.java	15 Apr 2002 12:11:47 -0000	1.17
  +++ TraXLiaison.java	24 May 2002 15:47:57 -0000	1.17.2.1
  @@ -80,6 +80,7 @@
   import javax.xml.transform.stream.StreamSource;
   import javax.xml.transform.OutputKeys;
   import javax.xml.transform.Source;
  +import javax.xml.transform.URIResolver;
   
   import javax.xml.transform.sax.SAXSource;
   
  @@ -108,7 +109,10 @@
       private XSLTLogger logger;
       
       /** possible resolver for publicIds */
  -    private EntityResolver resolver;
  +    private EntityResolver entityResolver;
  +
  +    /** possible resolver for URIs */
  +    private URIResolver uriResolver;
   
       public TraXLiaison() throws Exception {
           tfactory = TransformerFactory.newInstance();
  @@ -145,12 +149,12 @@
               // FIXME: need to use a SAXSource as the source for the transform
               // so we can plug in our own entity resolver
               Source src = null;
  -            if (resolver != null) {
  +            if (entityResolver != null) {
                   if (tfactory.getFeature(SAXSource.FEATURE)) {
                       SAXParserFactory spFactory = SAXParserFactory.newInstance();
                       spFactory.setNamespaceAware(true); 
                       XMLReader reader = spFactory.newSAXParser().getXMLReader();
  -                    reader.setEntityResolver(resolver);
  +                    reader.setEntityResolver(entityResolver);
                       src = new SAXSource(reader, new InputSource(fis));
                   } else {
                       throw new IllegalStateException("xcatalog specified, but " +
  @@ -164,6 +168,9 @@
               // not sure what could be the need of this...
               res.setSystemId(getSystemId(outfile));
   
  +            if (uriResolver != null)
  +                transformer.setURIResolver(uriResolver);
  +
               transformer.transform(src, res);
           } finally {
               // make sure to close all handles, otherwise the garbage
  @@ -263,7 +270,13 @@
       /** Set the class to resolve entities during the transformation
        */
       public void setEntityResolver(EntityResolver aResolver) throws Exception {
  -        resolver = aResolver;
  +        entityResolver = aResolver;
  +    }
  +
  +    /** Set the class to resolve URIs during the transformation
  +     */
  +    public void setURIResolver(URIResolver aResolver) throws Exception {
  +        uriResolver = aResolver;
       }
       
   } //-- TraXLiaison
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +127 -31   jakarta-ant/docs/manual/CoreTypes/xmlcatalog.html
  
  Index: xmlcatalog.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/CoreTypes/xmlcatalog.html,v
  retrieving revision 1.1
  retrieving revision 1.1.2.1
  diff -u -r1.1 -r1.1.2.1
  --- xmlcatalog.html	21 Mar 2002 08:58:09 -0000	1.1
  +++ xmlcatalog.html	24 May 2002 15:47:57 -0000	1.1.2.1
  @@ -8,38 +8,112 @@
   <body>
   
   <h2><a name="XMLCatalog">XMLCatalog</a></h2>
  -<p>An XMLCatalog is a catalog of public resources such as DTDs or entities 
  -that
  -are referenced in an XML document and are available locally.</p>
  -<p>This allows the XML Parser, XSL Processor or other consumer of XML 
  +
  +<p>An XMLCatalog is a catalog of public resources such as DTDs or
  +entities that are referenced in an XML document.  Catalogs are
  +typically used to make web references to resources point to a locally
  +cached copy of the resource.</p>
  +
  +<p>This allows the XML Parser, XSLT Processor or other consumer of XML 
   documents
   to efficiently allow a local substitution for a resource available on the 
   web.
   </p>
  +<p>This data type provides a catalog of resource locations based
  +on the <a
  +href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
  +OASIS "Open Catalog" standard</a>.  The catalog entries are used
  +both for Entity resolution and URI resolution, in accordance with
  +the <code>org.xml.sax.EntityResolver</code> and <code>
  +javax.xml.transform.URIResolver</code> interfaces as defined
  +in the <a href="http://java.sun.com/xml/jaxp">Java API for XML
  +Processing (JAXP) Specification</a>.</p>
   <p>For example, in a <code>web.xml</code> file, the DTD is referenced as:
   <pre>
  -&lt;!DOCTYPE web-app
  -  PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 
  -2.2//EN&quot;
  +&lt;!DOCTYPE web-app PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN&quot;
     &quot;http://java.sun.com/j2ee/dtds/web-app_2_2.dtd&quot;&gt;
   </pre>
   The XML processor, without XMLCatalog support, would need to retrieve the 
   DTD from
   the URL specified whenever validation of the document was required.
   </p>
  -<p>This can be very time consuming during the build process, especially 
  -where 
  -network throughput is limited.</p>
  +<p>This can be very time consuming during the build process,
  +especially where network throughput is limited.  Alternatively, you
  +can do the following:
  +<ol>
  +<li>Copy <code>web-app_2_2.dtd</code> onto your local disk somewhere (either in the
  +filesystem or even embedded inside a jar or zip file on the classpath).</li>
  +<li>Create an <code>&lt;xmlcatalog&gt;</code> with a <code>&lt;dtd&gt;</code> 
  +element whose <code>location</code> attribute points to the file.</li>
  +<li>Success! The XML processor will now use the local copy instead of calling out
  +to the internet.</li>
  +</ol>
   </p>
   <p>XMLCatalogs can appear inside tasks
   that support this feature or at the same level as <code>target</code>
   - i.e., as children of <code>project</code> for reuse across different 
   tasks,
  -e.g. XML Validation and XSL Translation.</p>
  +e.g. XML Validation and XSLT Transformation.  The XML Validate task
  +uses XMLCatalogs for entity resolution.  The XSLT Transformation
  +task uses XMLCatalogs for both entity and URI resolution.</p>
   <p>XMLCatalogs are specified as either a reference to another XMLCatalog, 
   defined
   previously in a build file, or as a list of <code>dtd</code> or
  -<code>entity</code> locations.</p>
  +<code>entity</code> locations.  A separate classpath for entity resolution 
  +may be specified inline via nested <code>classpath</code> elements; 
  +otherwise the system classpath is used for this as well.</p>
  +<p>XMLCatalogs can also be nested inside other XMLCatalogs.  For
  +example, a "superset" XMLCatalog could be made by including several
  +nested XMLCatalogs that referred to other, previously defined
  +XMLCatalogs.</p>
  +<p>Currently, only <code>&lt;dtd&gt;</code> and
  +<code>&lt;entity&gt;</code> elements may be specified inline; these
  +roughly correspond to OASIS catalog entry types <code>PUBLIC</code> and
  +<code>URI</code> respectively.</p>  
  +<h3><a name="ResolverAlgorithm">Entity/DTD/URI Resolution Algorithm</a></h3>
  +
  +When an entity, DTD, or URI is looked up by the XML processor, the
  +XMLCatalog searches its list of entries to see if any match.  That is,
  +it attempts to match the <code>publicId</code> attribute of each entry
  +with the PublicID or URI of the entity to be resolved.  Assuming a
  +matching entry is found, XMLCatalog then executes the following steps:
  +
  +<h4>1. Filesystem lookup</h4>
  +
  +<p>The <code>location</code> is first looked up in the filesystem.  If
  +the <code>location</code> is a relative path, the ant project basedir
  +attribute is used as the base directory.  If the <code>location</code>
  +specifies an absolute path, it is used as is.  Once we have an
  +absolute path in hand, we check to see if a valid and readable file
  +exists at that path.  If so, we are done.  If not, we proceed to the
  +next step.</p>
  +
  +<h4>2. Classpath lookup</h4>
  +
  +<p>The <code>location</code> is next looked up in the classpath.
  +Recall that jar files are merely fancy zip files.  For classpath
  +lookup, the <code>location</code> is used as is (no base is
  +prepended).  We use a Classloader to attempt to load the resource from
  +the classpath.  For example, if hello.jar is in the classpath and it
  +contains <code>foo/bar/blat.dtd</code> it will resolve an entity whose
  +<code>location</code> is <code>foo/bar/blat.dtd</code>.  Of course, it
  +will <em>not</em> resolve an entity whose <code>location</code> is
  +<code>blat.dtd</code>.
  +
  +
  +<h4>3. URL-space lookup</h4>
  +
  +<p>Finally, we attempt to make a URL out of the <code>location</code>.
  +At first this may seem like this would defeat the purpose of
  +XMLCatalogs -- why go back out to the internet?  But in fact, this can
  +be used to (in a sense) implement HTTP redirects, substituting one URL
  +for another.  The mapped-to URL might also be served by a local web
  +server.  If the URL resolves to a valid and readable resource, we are
  +done.  Otherwise, we give up.  In this case, the XML processor will
  +perform its normal resolution algorithm.  Depending on the processor
  +configuration, further resolution failures may or may not result in
  +fatal (i.e. build-ending) errors.</p>
  +
   <h3>XMLCatalog attributes</h3>
   <table border="1" cellpadding="2" cellspacing="0">
     <tr>
  @@ -64,6 +138,7 @@
   </table>
   
   <h3>XMLCatalog nested elements</h3>
  +<h4>dtd/entity</h4>
   <p>The <code>dtd</code> and <code>entity</code> elements used to specify
   XMLCatalogs are identical in their structure</p>
   <table border="1" cellpadding="2" cellspacing="0">
  @@ -84,46 +159,67 @@
     <tr>
       <td valign="top">location</td>
       <td valign="top">The location of the local replacement to be used for 
  -the
  -    public identifier specified. This may be specified as a file name, 
  -resource
  -    name found on the classpath, or a URL
  +the public identifier specified. This may be specified as a file name, 
  +resource name found on the classpath, or a URL.  Relative paths will
  +be resolved according to the base, which by default is the Ant project
  +basedir.
       </td>
       <td valign="top" align="center">Yes</td>
     </tr>
   </table>
  -<h3>Examples</h4>
  +<h4>classpath</h4>
  +<p>The classpath to use for <a href="#ResolverAlgorithm">entity
  +resolution</a>.  The nested <code>&lt;classpath&gt;</code> is a
  +<a href="../using.html#path">path</a>-like structure.</p>
  +<h3>Examples</h3>
   <p>Set up an XMLCatalog with a single dtd referenced locally in a user's 
   home 
   directory:</p>
   <blockquote><pre>
       &lt;xmlcatalog&gt;
  -        &lt;dtd publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
  - location=&quot;/home/dion/downloads/docbook/docbookx.dtd&quot;/&gt;
  +        &lt;dtd 
  +            publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
  +            location=&quot;/home/dion/downloads/docbook/docbookx.dtd&quot;/&gt;
       &lt;/xmlcatalog&gt;
   </pre></blockquote>
  -<p>Set up an XMLCatalog with a multiple dtds referenced locally in a 
  -user's home 
  -directory:</p>
  +<p>Set up an XMLCatalog with a multiple dtds to be found either in the
  +filesystem (relative to the Ant project basedir) or in the classpath:
  +</p>
   <blockquote><pre>
       &lt;xmlcatalog id=&quot;commonDTDs&quot;&gt;
  -        &lt;dtd publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
  - location=&quot;/home/dion/downloads/docbook/docbookx.dtd&quot;/&gt;
  -        &lt;dtd publicId=&quot;-//Sun Microsystems, Inc.//DTD Web 
  -Application 2.2//EN&quot;
  -             location=&quot;/home/dion/web-app_2_2.dtd&quot;/&gt;
  +        &lt;dtd 
  +            publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
  +            location=&quot;docbook/docbookx.dtd&quot;/&gt;
  +        &lt;dtd 
  +            publicId=&quot;-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN&quot;
  +            location=&quot;web-app_2_2.dtd&quot;/&gt;
  +    &lt;/xmlcatalog&gt;
  +</pre></blockquote>
  +
  +<p>Set up an XMLCatalog with a combination of DTDs and entities as
  +well as a nested XMLCatalog:</p>
  +
  +<blockquote><pre>
  +    &lt;xmlcatalog id=&quot;allcatalogs&quot;&gt;
  +        &lt;dtd 
  +            publicId=&quot;-//ArielPartners//DTD XML Article V1.0//EN&quot;
  +            location=&quot;com/arielpartners/knowledgebase/dtd/article.dtd&quot;/&gt;
  +        &lt;entity 
  +            publicId=&quot;LargeLogo&quot;
  +            location=&quot;com/arielpartners/images/ariel-logo-large.gif&quot;/&gt;
  +	&lt;xmlcatalog refid="commonDTDs"/&gt;
       &lt;/xmlcatalog&gt;
   </pre></blockquote>
  -<p>To reference the above xmlcatalog in a style task:<p>
  +<p>To reference the above XMLCatalog in an <code>xslt</code> task:<p>
   <blockquote><pre>
  -    &lt;style basedir="${source.doc}"
  +    &lt;xslt basedir="${source.doc}"
              destdir="${dest.xdocs}"
              extension=".xml"
              style="${source.xsl.converter.docbook}"
              includes="**/*.xml"
              force="true"&gt;
  -        &lt;xmlcatalog refid=&quot;commonDTDs&quot;/&gt;
  -    &lt;/style&gt;
  +        &lt;xmlcatalog refid=&quot;allcatalogs&quot;/&gt;
  +    &lt;/xslt&gt;
   </pre></blockquote>
   
   <hr>
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +484 -0    jakarta-ant/src/testcases/org/apache/tools/ant/types/Attic/XMLCatalogTest.java
  
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>