1 16 package org.apache.cocoon.generation; 17 18 import java.io.IOException ; 19 import java.util.HashMap ; 20 import java.util.Map ; 21 22 import org.apache.avalon.framework.logger.Logger; 23 import org.apache.avalon.framework.parameters.Parameters; 24 import org.apache.avalon.framework.service.ServiceException; 25 import org.apache.avalon.framework.service.ServiceManager; 26 import org.apache.cocoon.ProcessingException; 27 import org.apache.cocoon.components.source.SourceUtil; 28 import org.apache.cocoon.environment.Context; 29 import org.apache.cocoon.environment.ObjectModelHelper; 30 import org.apache.cocoon.environment.SourceResolver; 31 import org.apache.cocoon.xml.dom.DOMStreamer; 32 import org.apache.excalibur.source.TraversableSource; 33 import org.apache.excalibur.xml.xpath.PrefixResolver; 34 import org.apache.excalibur.xml.xpath.XPathProcessor; 35 import org.apache.regexp.RE; 36 import org.apache.regexp.RESyntaxException; 37 import org.w3c.dom.Document ; 38 import org.w3c.dom.NodeList ; 39 import org.xml.sax.SAXException ; 40 import org.xml.sax.helpers.AttributesImpl ; 41 42 98 public class XPathTraversableGenerator extends TraversableGenerator { 99 100 101 protected static final String XPATH_NODE_NAME = "xpath"; 102 103 protected static final String QUERY_ATTR_NAME = "query"; 104 105 protected static final String RESULT_DOCID_ATTR = "docid"; 106 107 108 protected RE xmlRE; 109 110 111 protected Document doc; 112 113 114 protected String xpath; 115 116 117 protected XPathProcessor processor; 118 119 120 protected XPathPrefixResolver prefixResolver; 121 122 123 protected Context context; 124 125 126 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) 127 throws ProcessingException, SAXException , IOException { 128 super.setup(resolver, objectModel, src, par); 129 130 int pointer; 132 if ((pointer = this.source.indexOf("#")) != -1) { 133 int endpointer = this.source.indexOf('?'); 134 if (endpointer != -1) { 135 this.xpath = source.substring(pointer + 1, endpointer); 136 } else { 137 this.xpath = source.substring(pointer + 1); 138 } 139 this.source = src.substring(0, pointer); 140 if (endpointer != -1) { 141 this.source += src.substring(endpointer); 142 } 143 } else { 144 this.xpath = par.getParameter("xpath", null); 145 } 146 this.cacheKeyParList.add(this.xpath); 147 if (getLogger().isDebugEnabled()) { 148 getLogger().debug("Applying XPath: " + xpath + " to collection " + source); 149 } 150 151 String xmlFilesPattern = null; 152 try { 153 xmlFilesPattern = par.getParameter("xmlFiles", "\\.xml$"); 154 this.cacheKeyParList.add(xmlFilesPattern); 155 this.xmlRE = new RE(xmlFilesPattern); 156 if (this.getLogger().isDebugEnabled()) { 157 this.getLogger().debug("pattern for XML files: " + xmlFilesPattern); 158 } 159 } catch (RESyntaxException rese) { 160 throw new ProcessingException("Syntax error in regexp pattern '" 161 + xmlFilesPattern + "'", rese); 162 } 163 164 String [] params = par.getNames(); 165 this.prefixResolver = new XPathPrefixResolver(this.getLogger()); 166 for (int i = 0; i < params.length; i++) { 167 if (params[i].startsWith("xmlns:")) { 168 String paramValue = par.getParameter(params[i], ""); 169 String paramName = params[i].substring(6); 170 if (getLogger().isDebugEnabled()) { 171 getLogger().debug("add param to prefixResolver: " + paramName); 172 } 173 this.prefixResolver.addPrefix(paramName, paramValue); 174 } 175 } 176 177 this.context = ObjectModelHelper.getContext(objectModel); 178 } 179 180 public void service(ServiceManager manager) throws ServiceException { 181 super.service(manager); 182 processor = (XPathProcessor)manager.lookup(XPathProcessor.ROLE); 183 } 184 185 public void dispose() { 186 if ( this.manager != null ) { 187 this.manager.release( processor ); 188 this.processor = null; 189 } 190 super.dispose(); 191 } 192 193 protected void addContent(TraversableSource source) 194 throws SAXException , ProcessingException { 195 super.addContent(source); 196 if (!source.isCollection() && isXML(source) && xpath != null) { 197 performXPathQuery(source); 198 } 199 } 200 201 208 protected boolean isXML(TraversableSource path) { 209 String mimeType = this.context.getMimeType(path.getName()); 210 return this.xmlRE.match(path.getName()) || "text/xml".equalsIgnoreCase(mimeType); 211 } 212 213 218 protected void performXPathQuery(TraversableSource in) throws SAXException { 219 doc = null; 220 try { 221 doc = SourceUtil.toDOM(this.manager, "text/xml", in); 222 } catch (SAXException se) { 223 getLogger().error("Warning:" + in.getName() + " is not a valid XML document. Ignoring"); 224 } catch (Exception e) { 225 this.getLogger().error("Unable to resolve and parse document" + e); 226 } 227 if (doc != null) { 228 NodeList nl = processor.selectNodeList(doc.getDocumentElement(), xpath, this.prefixResolver); 229 final String id = in.getName(); 230 AttributesImpl attributes = new AttributesImpl (); 231 attributes.addAttribute("", RESULT_DOCID_ATTR, RESULT_DOCID_ATTR," CDATA", id); 232 attributes.addAttribute("", QUERY_ATTR_NAME, QUERY_ATTR_NAME, "CDATA",xpath); 233 super.contentHandler.startElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME, attributes); 234 DOMStreamer ds = new DOMStreamer(super.xmlConsumer); 235 for (int i = 0; i < nl.getLength(); i++) { 236 ds.stream(nl.item(i)); 237 } 238 super.contentHandler.endElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME); 239 } 240 } 241 242 246 public void recycle() { 247 this.xpath = null; 248 this.doc = null; 249 this.xmlRE = null; 250 this.prefixResolver = null; 251 this.context = null; 252 super.recycle(); 253 } 254 255 258 static class XPathPrefixResolver implements PrefixResolver { 259 260 private Map params; 261 262 private Logger logger; 263 264 public XPathPrefixResolver(Logger logger) { 265 this.params = new HashMap (); 266 this.logger = logger; 267 } 268 269 274 public String prefixToNamespace(String prefix) { 275 if (this.logger.isDebugEnabled()) { 276 this.logger.debug("prefix: " + prefix); 277 } 278 if (this.params.containsKey(prefix)) { 279 if(this.logger.isDebugEnabled()) { 280 this.logger.debug("prefix; " + prefix + " - namespace: " + this.params.get(prefix)); 281 } 282 return (String ) this.params.get(prefix); 283 } 284 return null; 285 } 286 287 public void addPrefix(String prefix, String uri) { 288 this.params.put(prefix, uri); 289 } 290 } 291 } 292 | Popular Tags |