You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by gi...@apache.org on 2003/07/13 14:33:53 UTC

cvs commit: cocoon-2.1/src/scratchpad/src/org/apache/cocoon/generation XPathTraversableGenerator.java

gianugo     2003/07/13 05:33:53

  Modified:    src/scratchpad/src/org/apache/cocoon/generation
                        XPathTraversableGenerator.java
  Log:
  Sterted refactoring to sync with XPathDirectoryGenerator. This version is
  still using addPath() since a planned feature (excluding from listing non
  matched resources) couldn't work the other way, but it will be taken into
  account shortly. From a user point of view, anyway, now using XDG or XTG
  should be absolutely transparent.
  
  Revision  Changes    Path
  1.2       +96 -39    cocoon-2.1/src/scratchpad/src/org/apache/cocoon/generation/XPathTraversableGenerator.java
  
  Index: XPathTraversableGenerator.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/scratchpad/src/org/apache/cocoon/generation/XPathTraversableGenerator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XPathTraversableGenerator.java	10 Jul 2003 08:12:49 -0000	1.1
  +++ XPathTraversableGenerator.java	13 Jul 2003 12:33:53 -0000	1.2
  @@ -57,6 +57,7 @@
   import java.util.HashMap;
   import java.util.Map;
   
  +import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.cocoon.ProcessingException;
  @@ -67,26 +68,41 @@
   import org.apache.excalibur.xml.dom.DOMParser;
   import org.apache.excalibur.xml.xpath.PrefixResolver;
   import org.apache.excalibur.xml.xpath.XPathProcessor;
  +import org.apache.regexp.RE;
  +import org.apache.regexp.RESyntaxException;
  +
   import org.w3c.dom.Document;
   import org.w3c.dom.NodeList;
  +
   import org.xml.sax.InputSource;
   import org.xml.sax.SAXException;
   import org.xml.sax.helpers.AttributesImpl;
   
   /**
  - * Generates an XML directory listing performing XPath queries
  - * on XML files. It can be used both as a plain TraversableGenerator
  - * or, using an "xpointerinsh" syntax it will perform an XPath
  - * query on every XML resource.
  + * Generates an XML collection listing performing XPath queries on XML sources.
  + * It can be used both as a plain TraversableGenerator or, if an XPath is
  + * specified, it will perform an XPath query on every XML resource, where "xml
  + * resource" is, by default, any resource ending with ".xml", which can be
  + * overriden by setting the (regexp) pattern "xmlFiles as a sitemap parameter.
  + * 
  + * The XPath can be specified in two ways:
  + * <ol>
  + *    <li>By using an XPointerish syntax in the URL: everything following the
  + *         pound                 sign                 (possiby preceding  query
  + * string arguments)  will be treated as the XPath;
  + *     </li>
  + *     <li>Specifying it as a sitemap parameter named "xpath"
  + *  </ol>
    *
    * Sample usage:
    *
    * Sitemap:
    * &lt;map:match pattern="documents/**"&gt;
    *   &lt;map:generate type="xpathdirectory"
  - *     src="docs/{1}#/article/title|/article/abstract" /&gt;
  - *   &lt;map:serialize type="xml" /&gt;
  - * &lt;/map:match&gt;
  + *     src="    docs/{1}#/article/title|/article/abstract" &gt;
  + *     &lt;          map:parameter name="xmlFiles" value="\.xml$"/&gt;   
  + * &lt;/map:generate&gt;
  + * &lt;map: serialize type="xml" /&gt; &lt;/map:match&gt;
    *
    * Request:
    *   http://www.some.host/documents/test
  @@ -117,19 +133,26 @@
    */
   public class XPathTraversableGenerator extends TraversableGenerator {
   
  -    /** Element &lt;result&gt; */
  -    protected static final String RESULT = "xpath";
  -    protected static final String QRESULT = PREFIX + ":" + RESULT;
  -    protected static final String RESULT_DOCID_ATTR = "docid";
  -    protected static final String QUERY_ATTR = "query";
  -
  -    protected static final String CDATA  = "CDATA";
  -    protected String XPathQuery = null;
  -    protected XPathProcessor processor = null;
  -    protected DOMParser parser;
  -    protected Document doc;
  -    private XPathPrefixResolver prefixResolver;
  -	
  +	/** Local name for the element that contains the included XML snippet. */
  +	protected static final String XPATH_NODE_NAME = "xpath";
  +	/** Attribute for the XPath query. */
  +	protected static final String QUERY_ATTR_NAME = "query";
  +	/** The document containing a successful XPath query */
  +	protected static final String RESULT_DOCID_ATTR = "docid";
  +
  +	/** The regular expression for the XML files pattern. */
  +	protected RE xmlRE = null;
  +	/** The document that should be parsed and (partly) included. */
  +	protected Document doc = null;
  +	/** The XPath. */
  +	protected String xpath = null;
  +	/** The XPath processor. */
  +	protected XPathProcessor processor = null;
  +	/** The parser for the XML snippets to be included. */
  +	protected DOMParser parser = null;
  +   /** The prefix resolver for namespaced queries */
  +	protected XPathPrefixResolver prefixResolver;
  +	 	
       public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
           throws ProcessingException, SAXException, IOException {
           super.setup(resolver, objectModel, src, par);
  @@ -138,18 +161,39 @@
           if ((pointer = this.source.indexOf("#")) != -1) {
             int endpointer = this.source.indexOf('?');
             if (endpointer != -1) {
  -          	this.XPathQuery = source.substring(pointer + 1, endpointer); 
  +          	this.xpath = source.substring(pointer + 1, endpointer); 
             } else {
  -			this.XPathQuery = source.substring(pointer + 1);
  +			this.xpath = source.substring(pointer + 1);
             }
             this.source = src.substring(0, pointer);
  -          if (endpointer != -1)
  +          if (endpointer != -1) {
             	this.source += src.substring(endpointer);
  +          }
  +		  
  +		  this.cacheKeyParList.add(this.xpath); 	
             if (this.getLogger().isDebugEnabled())
  -            this.getLogger().debug("Applying XPath: " + XPathQuery
  +            this.getLogger().debug("Applying XPath: " + xpath
                 + " to collection " + source);
  +        } else {
  +			this.xpath = par.getParameter("xpath", null);
  +			this.cacheKeyParList.add(this.xpath);
  +			this.getLogger().debug("Applying XPath: " + xpath
  +			   + " to collection " + source);
           }
           
  +		String xmlFilesPattern = null;
  +		try {
  +			xmlFilesPattern = par.getParameter("xmlFiles", "\\.xml$");
  +			this.cacheKeyParList.add(xmlFilesPattern);
  +			this.xmlRE = new RE(xmlFilesPattern);
  +			if (this.getLogger().isDebugEnabled()) {
  +				this.getLogger().debug("pattern for XML files: " + xmlFilesPattern);
  +			}
  +		} catch (RESyntaxException rese) {
  +			throw new ProcessingException("Syntax error in regexp pattern '"
  +										  + xmlFilesPattern + "'", rese);
  +		}
  +        
           String[] params = par.getNames();
           this.prefixResolver = new XPathPrefixResolver();
           for (int i = 0; i < params.length; i++) {
  @@ -164,14 +208,10 @@
           }
       }
   
  -    public void compose(ComponentManager manager) {
  -      try {
  +    public void compose(ComponentManager manager) throws ComponentException {
           super.compose(manager);
           processor = (XPathProcessor)manager.lookup(XPathProcessor.ROLE);
           parser = (DOMParser)manager.lookup(DOMParser.ROLE);
  -      } catch (Exception e) {
  -        this.getLogger().error("Could not obtain a required component", e);
  -      }
       }
   
       /**
  @@ -233,7 +273,7 @@
   								new Long(((TraversableSource)o2).getLastModified()));
   						}
   					});
  -				} else if (sort.equals("directory")) {
  +				} else if (sort.equals("collection")) {
   					Arrays.sort(contents.toArray(), new Comparator() {
   						public int compare(Object o1, Object o2) {
   							TraversableSource ts1 = (TraversableSource)o1;
  @@ -265,12 +305,29 @@
   		} else {
   			if (isIncluded(path) && !isExcluded(path)) {
   				startNode(RESOURCE_NODE_NAME, path);
  -				if (path.getName().endsWith(".xml") && XPathQuery != null)
  +				if (isXML(path)  && xpath != null)
   				  performXPathQuery(path);
   				endNode(RESOURCE_NODE_NAME);
   			}
   		}
       }
  +    
  +	/**
  +	 * Determines if a given TraversableSource shall be handled as XML.
  +	 *
  +	 * @param path  the TraversableSource to check
  +	 * @return true  if the given TraversableSource shall handled as XML, false
  +	 * otherwise.
  +	 */
  +	protected boolean isXML(TraversableSource path) {
  +		return this.xmlRE.match(path.getName());
  +	}
  +	
  +	/**
  +	 * Performs an XPath query on the source.
  +	 * @param xmlFile  the Source the XPath is performed on.
  +	 * @throws SAXException  if something goes wrong while adding the XML snippet.
  +	 */
   
       protected void performXPathQuery(TraversableSource in)
         throws SAXException {
  @@ -284,18 +341,18 @@
            this.getLogger().error("Unable to resolve and parse document" + e);
          }
          if (doc != null) {
  -         NodeList nl = processor.selectNodeList(doc.getDocumentElement(), XPathQuery, this.prefixResolver);
  +         NodeList nl = processor.selectNodeList(doc.getDocumentElement(), xpath, this.prefixResolver);
            final String id = in.getName();
            AttributesImpl attributes = new AttributesImpl();
            attributes.addAttribute("", RESULT_DOCID_ATTR, RESULT_DOCID_ATTR,
  -           CDATA, id);
  -         attributes.addAttribute("", QUERY_ATTR, QUERY_ATTR, CDATA,
  -           XPathQuery);
  -         super.contentHandler.startElement(URI, RESULT, QRESULT, attributes);
  +          " CDATA", id);
  +         attributes.addAttribute("", QUERY_ATTR_NAME, QUERY_ATTR_NAME, "CDATA",
  +           xpath);
  +         super.contentHandler.startElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME, attributes);
            DOMStreamer ds = new DOMStreamer(super.xmlConsumer);
            for (int i = 0; i < nl.getLength(); i++)
              ds.stream(nl.item(i));
  -         super.contentHandler.endElement(URI, RESULT, QRESULT);
  +         super.contentHandler.endElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME);
         }
       }
   
  @@ -305,7 +362,7 @@
        */
      public void recycle() {
         super.recycle();
  -      this.XPathQuery = null;
  +      this.xpath = null;
         this.attributes = null;
         this.doc = null;
       }