1 16 package org.apache.cocoon.generation; 17 18 import java.io.BufferedReader ; 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.io.InputStreamReader ; 22 import java.util.HashMap ; 23 import java.util.Map ; 24 25 import org.apache.avalon.framework.logger.Logger; 26 import org.apache.avalon.framework.parameters.Parameters; 27 import org.apache.avalon.framework.service.ServiceException; 28 import org.apache.avalon.framework.service.ServiceManager; 29 import org.apache.cocoon.ProcessingException; 30 31 import org.apache.cocoon.components.source.SourceUtil; 32 33 import org.apache.cocoon.environment.SourceResolver; 34 35 import org.apache.cocoon.xml.dom.DOMStreamer; 36 37 import org.apache.excalibur.source.Source; 38 import org.apache.excalibur.source.SourceNotFoundException; 39 40 import org.apache.excalibur.xml.dom.DOMParser; 41 import org.apache.excalibur.xml.xpath.PrefixResolver; 42 import org.apache.excalibur.xml.xpath.XPathProcessor; 43 44 import org.apache.regexp.RE; 45 import org.apache.regexp.RESyntaxException; 46 47 import org.w3c.dom.Document ; 48 import org.w3c.dom.NodeList ; 49 50 import org.xml.sax.SAXException ; 51 52 import org.xml.sax.helpers.AttributesImpl ; 53 54 55 128 public class XPathDirectoryGenerator 129 extends DirectoryGenerator { 130 131 protected static final String XPATH_NODE_NAME = "xpath"; 132 133 134 protected static final String QUERY_ATTR_NAME = "query"; 135 136 137 protected static final Map mappingFiles = new HashMap (); 138 139 140 protected DOMParser parser = null; 141 142 143 protected Document doc = null; 144 145 146 protected PrefixResolver prefixResolver = null; 147 148 149 protected RE xmlRE = null; 150 151 152 protected String xpath = null; 153 154 155 protected XPathProcessor processor = null; 156 157 160 public void dispose() { 161 if (this.manager != null) { 162 this.manager.release(this.processor); 163 this.manager.release(this.parser); 164 this.processor = null; 165 this.parser = null; 166 } 167 168 super.dispose(); 169 } 170 171 174 public void recycle() { 175 this.xpath = null; 176 this.doc = null; 177 178 super.recycle(); 181 } 182 183 190 public void service(ServiceManager manager) 191 throws ServiceException { 192 super.service(manager); 193 this.processor = (XPathProcessor)manager.lookup(XPathProcessor.ROLE); 194 this.parser = (DOMParser)manager.lookup(DOMParser.ROLE); 195 } 196 197 209 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) 210 throws ProcessingException, SAXException , IOException { 211 super.setup(resolver, objectModel, src, par); 212 213 this.xpath = par.getParameter("xpath", null); 215 this.cacheKeyParList.add(this.xpath); 216 217 if (getLogger().isDebugEnabled()) { 218 getLogger().debug("Applying XPath: " + this.xpath + " to directory " + this.source); 219 } 220 221 final String mappings = par.getParameter("nsmapping", null); 222 223 if (null != mappings) { 224 final boolean mapping_reload = par.getParameterAsBoolean("nsmapping-reload", false); 225 final Source mappingSource = resolver.resolveURI(mappings); 226 final String mappingKey = mappingSource.getURI(); 227 final MappingInfo mappingInfo = (MappingInfo)XPathDirectoryGenerator.mappingFiles.get(mappingKey); 228 229 if ((null == mappingInfo) || (mappingInfo.reload == false) || 230 (mappingInfo.mappingSource.getLastModified() < mappingSource.getLastModified())) { 231 this.prefixResolver = 232 new MappingInfo(getLogger().getChildLogger("prefix-resolver"), mappingSource, mapping_reload); 233 XPathDirectoryGenerator.mappingFiles.put(mappingKey, this.prefixResolver); 234 } else { 235 this.prefixResolver = mappingInfo; 236 } 237 } 238 239 String xmlFilesPattern = null; 240 241 try { 242 xmlFilesPattern = par.getParameter("xmlFiles", "\\.xml$"); 243 this.cacheKeyParList.add(xmlFilesPattern); 244 this.xmlRE = new RE(xmlFilesPattern); 245 246 if (getLogger().isDebugEnabled()) { 247 getLogger().debug("pattern for XML files: " + xmlFilesPattern); 248 } 249 } catch (RESyntaxException rese) { 250 throw new ProcessingException("Syntax error in regexp pattern '" + xmlFilesPattern + "'", rese); 251 } 252 } 253 254 261 protected boolean isXML(File path) { 262 return this.xmlRE.match(path.getName()); 263 } 264 265 272 protected void performXPathQuery(File xmlFile) 273 throws SAXException { 274 this.doc = null; 275 276 Source source = null; 277 278 try { 279 source = resolver.resolveURI(xmlFile.toURL().toExternalForm()); 280 this.doc = this.parser.parseDocument(SourceUtil.getInputSource(source)); 281 } catch (SAXException e) { 282 getLogger().error("Warning:" + xmlFile.getName() + " is not a valid XML file. Ignoring.", e); 283 } catch (ProcessingException e) { 284 getLogger().error("Warning: Problem while reading the file " + xmlFile.getName() + ". Ignoring.", e); 285 } catch (IOException e) { 286 getLogger().error("Warning: Problem while reading the file " + xmlFile.getName() + ". Ignoring.", e); 287 } finally { 288 resolver.release(source); 289 } 290 291 if (doc != null) { 292 NodeList nl = 293 (null == this.prefixResolver) 294 ? this.processor.selectNodeList(this.doc.getDocumentElement(), this.xpath) 295 : this.processor.selectNodeList(this.doc.getDocumentElement(), this.xpath, this.prefixResolver); 296 AttributesImpl attributes = new AttributesImpl (); 297 attributes.addAttribute("", QUERY_ATTR_NAME, QUERY_ATTR_NAME, "CDATA", xpath); 298 super.contentHandler.startElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME, attributes); 299 300 DOMStreamer ds = new DOMStreamer(super.xmlConsumer); 301 302 for (int i = 0; i < nl.getLength(); i++) { 303 ds.stream(nl.item(i)); 304 } 305 306 super.contentHandler.endElement(URI, XPATH_NODE_NAME, PREFIX + ":" + XPATH_NODE_NAME); 307 } 308 } 309 310 318 protected void startNode(String nodeName, File path) 319 throws SAXException { 320 super.startNode(nodeName, path); 321 322 if ((this.xpath != null) && path.isFile() && this.isXML(path)) { 323 performXPathQuery(path); 324 } 325 } 326 327 333 private static class MappingInfo 334 implements PrefixResolver { 335 336 public final Source mappingSource; 337 338 339 public final boolean reload; 340 341 342 private final Logger logger; 343 344 345 private final Map prefixMap; 346 347 357 public MappingInfo(final Logger logger, final Source mappingSource, final boolean reload) 358 throws SourceNotFoundException, IOException { 359 this.logger = logger; 360 this.mappingSource = mappingSource; 361 this.reload = reload; 362 prefixMap = new HashMap (); 363 364 final BufferedReader br = new BufferedReader (new InputStreamReader (mappingSource.getInputStream())); 365 366 for (String line = br.readLine(); line != null; line = br.readLine()) { 367 final int i = line.indexOf('='); 368 369 if (i > 0) { 370 final String prefix = line.substring(0, i); 371 final String namespace = line.substring(i + 1); 372 prefixMap.put(prefix, namespace); 373 logger.debug("added mapping: '" + prefix + "'='" + namespace + "'"); 374 } 375 } 376 } 377 378 381 public String prefixToNamespace(String prefix) { 382 final String namespace = (String )this.prefixMap.get(prefix); 383 384 if (logger.isDebugEnabled()) { 385 logger.debug("have to resolve prefix='" + prefix + ", found namespace='" + namespace + "'"); 386 } 387 388 return namespace; 389 } 390 } 391 } 392 | Popular Tags |