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:
* <map:match pattern="documents/**">
* <map:generate type="xpathdirectory"
- * src="docs/{1}#/article/title|/article/abstract" />
- * <map:serialize type="xml" />
- * </map:match>
+ * src=" docs/{1}#/article/title|/article/abstract" >
+ * < map:parameter name="xmlFiles" value="\.xml$"/>
+ * </map:generate>
+ * <map: serialize type="xml" /> </map:match>
*
* Request:
* http://www.some.host/documents/test
@@ -117,19 +133,26 @@
*/
public class XPathTraversableGenerator extends TraversableGenerator {
- /** Element <result> */
- 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;
}