1 17 package org.apache.forrest.util; 18 19 import java.io.IOException ; 20 import java.io.Serializable ; 21 import java.util.Map ; 22 import java.util.Stack ; 23 24 import org.apache.avalon.framework.parameters.Parameters; 25 import org.apache.avalon.framework.service.ServiceManager; 26 import org.apache.avalon.framework.service.ServiceException; 27 import org.apache.cocoon.ProcessingException; 28 import org.apache.cocoon.transformation.AbstractDOMTransformer; 29 import org.apache.cocoon.caching.CacheableProcessingComponent; 30 import org.apache.cocoon.environment.SourceResolver; 31 import org.apache.cocoon.util.HashUtil; 32 import org.apache.excalibur.source.SourceValidity; 33 import org.apache.excalibur.source.impl.validity.NOPValidity; 34 import org.apache.excalibur.xml.dom.DOMParser; 35 import org.apache.excalibur.xml.xpath.XPathProcessor; 36 import org.w3c.dom.Attr ; 37 import org.w3c.dom.Document ; 38 import org.w3c.dom.Element ; 39 import org.w3c.dom.Node ; 40 import org.w3c.dom.NodeList ; 41 import org.xml.sax.SAXException ; 42 43 84 public class XPathTransformer 85 extends AbstractDOMTransformer 86 implements CacheableProcessingComponent 87 { 88 89 90 private XPathProcessor processor = null; 91 private DOMParser parser = null; 92 93 94 protected String include = null; 95 96 protected String exclude = null; 97 98 public void setup(SourceResolver resolver, Map objectModel, 99 String source, Parameters parameters) 100 throws ProcessingException, SAXException , IOException { 101 super.setup(resolver, objectModel, source, parameters); 102 this.include = parameters.getParameter("include", "/"); 103 this.exclude = parameters.getParameter("exclude", null); 104 } 105 106 107 public void service(ServiceManager manager) throws ServiceException { 108 super.service(manager); 109 try { 110 this.processor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE); 111 } catch (Exception e) { 112 getLogger().error("cannot obtain XPathProcessor", e); 113 } 114 try { 115 this.parser = (DOMParser)this.manager.lookup(DOMParser.ROLE); 116 } catch (Exception e) { 117 getLogger().error("cannot obtain DOMParser", e); 118 } 119 } 120 121 122 126 protected Document transform(Document doc) { 127 getLogger().debug("Transforming with include='"+include+"', exclude='"+exclude+"'"); 128 Document newDoc = null; 129 try { 130 newDoc = handleIncludes(doc, this.include); 131 newDoc = handleExcludes(newDoc, this.exclude); 132 } catch (SAXException se) { 133 getLogger().error("Error when transforming XML", se); 135 throw new RuntimeException ("Error transforming XML. See error log for details: "+se); 136 } 137 return newDoc; 138 } 139 140 146 private Document handleIncludes(Document doc, String xpath) throws SAXException { 147 if (xpath == null || xpath.equals("/")) { 148 return doc; 149 } 150 Document newDoc = parser.createDocument(); 151 NodeList nodes = processor.selectNodeList(doc, xpath); 152 for (int i=0; i<nodes.getLength(); i++) { 153 Node node = nodes.item(i); 154 addNode(newDoc, node); 155 } 156 return newDoc; 157 } 158 159 166 private Document handleExcludes(Document doc, String xpath) { 167 if (xpath == null || xpath.trim().equals("")) { 168 return doc; 169 } 170 NodeList nodes = processor.selectNodeList(doc, xpath); 171 for (int i = 0; i < nodes.getLength(); i++) { 172 Node node = nodes.item(i); 173 if (node.getNodeType() == Node.ATTRIBUTE_NODE) { 175 Attr attrNode = (Attr )node; 176 Element parent = attrNode.getOwnerElement(); 177 parent.removeAttributeNode(attrNode); 178 } else { 179 Node parent = node.getParentNode(); 180 if (parent != null) { 181 parent.removeChild(node); 182 } 183 } 184 } 185 return doc; 186 } 187 188 201 private void addNode(Document doc, final Node nodeTemplate) { 202 Stack stack = new Stack (); 204 Node parent = nodeTemplate; 205 Document oldDoc = nodeTemplate.getOwnerDocument(); 206 while (parent != oldDoc) { 207 stack.push(parent); 208 parent = parent.getParentNode(); 209 } 210 212 parent = doc; 216 while (!stack.empty()) { 217 Node oldNode = (Node )stack.pop(); 218 Node newNode = null; 219 if (!stack.empty()) { 220 newNode = doc.importNode(oldNode, false); copyNamespaceDeclarations(oldNode, newNode); 223 parent = findOrCreateNode(parent, newNode); 224 } else { 225 newNode = doc.importNode(oldNode, true); 227 copyNamespaceDeclarations(oldNode, newNode); 228 parent.appendChild(newNode); 229 } 230 } 231 } 232 233 242 private void copyNamespaceDeclarations(final Node oldNode, Node newNode) { 243 if (newNode.getNodeType() == Node.ELEMENT_NODE) { 244 String prefix = oldNode.getPrefix(); 245 String nsURI = oldNode.getNamespaceURI(); 246 Element newElem = (Element )newNode; 247 if (nsURI != null) { 248 if (prefix == null || prefix.equals("")) { 249 if (!newElem.hasAttribute("xmlns")) newElem.setAttribute("xmlns", nsURI); 250 } else { 251 if (!newElem.hasAttribute("xmlns:"+prefix)) newElem.setAttribute("xmlns:"+prefix, nsURI); 252 } 253 } 254 } 255 } 256 257 266 private Node findOrCreateNode(Node parent, Node newNode) { 267 NodeList otherChildren = parent.getChildNodes(); 268 for (int i = 0; i < otherChildren.getLength(); i++) { 269 Node child = otherChildren.item(i); 270 if (nodeEquality(child, newNode)) { 271 return child; 273 } 274 } 275 parent.appendChild(newNode); 277 return newNode; 278 } 279 280 291 private boolean nodeEquality(final Node n1, final Node n2) { 292 if (n1.getNodeType() != n2.getNodeType()) { 293 return false; 294 } 295 if (n1.getNodeName() == null) { 296 if (n2.getNodeName() != null) { 297 return false; 298 } 299 } 300 else if (!n1.getNodeName().equals(n2.getNodeName())) { 301 return false; 302 } 303 304 if (n1.getLocalName() == null) { 305 if (n2.getLocalName() != null) { 306 return false; 307 } 308 } 309 else if (!n1.getLocalName().equals(n2.getLocalName())) { 310 return false; 311 } 312 313 if (n1.getNamespaceURI() == null) { 314 if (n2.getNamespaceURI() != null) { 315 return false; 316 } 317 } 318 else if (!n1.getNamespaceURI().equals(n2.getNamespaceURI())) { 319 return false; 320 } 321 322 if (n1.getPrefix() == null) { 323 if (n2.getPrefix() != null) { 324 return false; 325 } 326 } 327 else if (!n1.getPrefix().equals(n2.getPrefix())) { 328 return false; 329 } 330 331 if (n1.getNodeValue() == null) { 332 if (n2.getNodeValue() != null) { 333 return false; 334 } 335 } 336 else if (!n1.getNodeValue().equals(n2.getNodeValue())) { 337 return false; 338 } 339 return true; 340 } 341 342 344 private final void printNode(String msg, Node node) { 345 getLogger().info(msg+" "+node.getNodeName()); 346 } 347 356 358 365 public Serializable getKey() { 366 return ""+HashUtil.hash(this.include+this.exclude); 367 } 368 public Serializable generateKey() { 370 return getKey(); 371 } 372 373 379 public SourceValidity getValidity() { 380 return new NOPValidity(); 381 } 382 383 public SourceValidity generateValidity() { 385 return getValidity(); 386 } 387 388 391 public void recycle() { 392 super.recycle(); 393 this.include = null; 394 this.exclude = null; 395 } 397 398 401 public void dispose() { 402 super.dispose(); 403 this.processor = null; 404 this.parser = null; 405 this.include = null; 406 this.exclude = null; 407 } 408 } 409 410 | Popular Tags |