1 16 package org.apache.cocoon.xml.dom; 17 18 import java.util.HashMap ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 22 import javax.xml.transform.Transformer ; 23 import javax.xml.transform.TransformerConfigurationException ; 24 import javax.xml.transform.TransformerException ; 25 import javax.xml.transform.TransformerFactory ; 26 import javax.xml.transform.dom.DOMSource ; 27 import javax.xml.transform.sax.SAXResult ; 28 29 import org.apache.cocoon.xml.AbstractXMLProducer; 30 import org.apache.cocoon.xml.EmbeddedXMLPipe; 31 import org.apache.cocoon.xml.XMLConsumer; 32 import org.apache.cocoon.xml.XMLProducer; 33 import org.apache.commons.lang.StringUtils; 34 35 import org.w3c.dom.Attr ; 36 import org.w3c.dom.Comment ; 37 import org.w3c.dom.Element ; 38 import org.w3c.dom.EntityReference ; 39 import org.w3c.dom.NamedNodeMap ; 40 import org.w3c.dom.Node ; 41 import org.w3c.dom.ProcessingInstruction ; 42 import org.w3c.dom.Text ; 43 import org.xml.sax.ContentHandler ; 44 import org.xml.sax.SAXException ; 45 import org.xml.sax.ext.LexicalHandler ; 46 import org.xml.sax.helpers.AttributesImpl ; 47 48 66 public class DOMStreamer implements XMLProducer { 67 68 69 private final static boolean DEFAULT_NORMALIZE_NAMESPACES = true; 70 71 72 protected boolean normalizeNamespaces = DEFAULT_NORMALIZE_NAMESPACES; 73 74 75 protected NamespaceNormalizingDOMStreamer namespaceNormalizingDOMStreamer = new NamespaceNormalizingDOMStreamer(); 76 77 78 protected DefaultDOMStreamer defaultDOMStreamer = new DefaultDOMStreamer(); 79 80 81 protected final static TransformerFactory factory = TransformerFactory.newInstance(); 82 83 86 public DOMStreamer() { 87 super(); 88 } 89 90 93 public DOMStreamer(XMLConsumer consumer) { 94 this(consumer, consumer); 95 } 96 97 100 public DOMStreamer(ContentHandler content) { 101 this(content, null); 102 if (content instanceof LexicalHandler ) { 103 defaultDOMStreamer.setLexicalHandler((LexicalHandler ) content); 104 namespaceNormalizingDOMStreamer.setLexicalHandler((LexicalHandler ) content); 105 } 106 } 107 108 111 public DOMStreamer(ContentHandler content, LexicalHandler lexical) { 112 this(); 113 defaultDOMStreamer.setContentHandler(content); 114 defaultDOMStreamer.setLexicalHandler(lexical); 115 namespaceNormalizingDOMStreamer.setContentHandler(content); 116 namespaceNormalizingDOMStreamer.setLexicalHandler(lexical); 117 } 118 119 122 public void setConsumer(XMLConsumer consumer) { 123 defaultDOMStreamer.setContentHandler(consumer); 124 defaultDOMStreamer.setLexicalHandler(consumer); 125 namespaceNormalizingDOMStreamer.setContentHandler(consumer); 126 namespaceNormalizingDOMStreamer.setLexicalHandler(consumer); 127 } 128 129 132 public void setContentHandler(ContentHandler handler) { 133 defaultDOMStreamer.setContentHandler(handler); 134 namespaceNormalizingDOMStreamer.setContentHandler(handler); 135 } 136 137 140 public void setLexicalHandler(LexicalHandler handler) { 141 defaultDOMStreamer.setLexicalHandler(handler); 142 namespaceNormalizingDOMStreamer.setLexicalHandler(handler); 143 } 144 145 148 public void stream(Node node) throws SAXException { 149 if (normalizeNamespaces) { 150 namespaceNormalizingDOMStreamer.stream(node); 151 } else { 152 defaultDOMStreamer.stream(node); 153 } 154 } 155 156 public boolean isNormalizeNamespaces() { 157 return normalizeNamespaces; 158 } 159 160 public void setNormalizeNamespaces(boolean normalizeNamespaces) { 161 this.normalizeNamespaces = normalizeNamespaces; 162 } 163 164 public void recycle() { 165 defaultDOMStreamer.recycle(); 166 namespaceNormalizingDOMStreamer.recycle(); 167 normalizeNamespaces = DEFAULT_NORMALIZE_NAMESPACES; 168 } 169 170 187 public static class NamespaceNormalizingDOMStreamer extends AbstractXMLProducer { 188 195 protected NamespaceNormalizingDOMStreamer.ElementInfo currentElementInfo = null; 196 197 198 protected int newPrefixCounter = 0; 199 200 public void recycle() { 201 super.recycle(); 202 currentElementInfo = null; 203 newPrefixCounter = 0; 204 } 205 206 219 protected void stream(Node pos) throws SAXException { 220 221 boolean isDoc = (pos.getNodeType() == Node.DOCUMENT_NODE); 223 if (isDoc) { 224 contentHandler.startDocument(); 225 } 226 227 Node top = pos; 228 while (null != pos) { 229 startNode(pos); 230 231 Node nextNode = pos.getFirstChild(); 232 while (null == nextNode) { 233 endNode(pos); 234 235 if (top.equals(pos)) { 236 break; 237 } 238 239 nextNode = pos.getNextSibling(); 240 if (null == nextNode) { 241 pos = pos.getParentNode(); 242 243 if ((null == pos) || (top.equals(pos))) { 244 if (null != pos) { 245 endNode(pos); 246 } 247 nextNode = null; 248 249 break; 250 } 251 } 252 } 253 254 pos = nextNode; 255 } 256 257 if (isDoc) { 258 contentHandler.endDocument(); 259 } 260 } 261 262 private final void dispatchChars(Node node) throws SAXException { 263 String data = ((Text ) node).getData(); 264 contentHandler.characters(data.toCharArray(), 0, data.length()); 265 } 266 267 272 protected void startNode(Node node) throws SAXException { 273 274 switch (node.getNodeType()) { 275 case Node.COMMENT_NODE: 276 { 277 if (lexicalHandler != null) { 278 String data = ((Comment ) node).getData(); 279 lexicalHandler.comment(data.toCharArray(), 0, data.length()); 280 } 281 } 282 break; 283 case Node.DOCUMENT_FRAGMENT_NODE: 284 285 break; 287 case Node.DOCUMENT_NODE: 288 289 break; 290 case Node.ELEMENT_NODE: 291 NamedNodeMap atts = node.getAttributes(); 292 int nAttrs = atts.getLength(); 293 294 currentElementInfo = new NamespaceNormalizingDOMStreamer.ElementInfo(currentElementInfo); 296 for (int i = 0; i < nAttrs; i++) { 297 Node attr = atts.item(i); 298 String attrName = attr.getNodeName(); 299 300 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) { 301 int index; 302 String prefix = (index = attrName.indexOf(":")) < 0 303 ? "" : attrName.substring(index + 1); 304 305 currentElementInfo.put(prefix, attr.getNodeValue()); 306 } 307 } 308 309 String namespaceURI = node.getNamespaceURI(); 310 String prefix = node.getPrefix(); 311 String localName = node.getLocalName(); 312 313 if (localName == null) { 314 String [] prefixAndLocalName = getPrefixAndLocalName(node.getNodeName()); 316 prefix = prefixAndLocalName[0]; 317 localName = prefixAndLocalName[1]; 318 namespaceURI = getNamespaceForPrefix(prefix, (Element )node); 320 } 321 322 if (namespaceURI != null) { 323 if (prefix == null) { 325 prefix = ""; 326 } 327 String uri = currentElementInfo.findNamespaceURI(prefix); 329 if (StringUtils.equals(uri, namespaceURI)) { 330 } else if (uri != null) { 333 currentElementInfo.put(prefix, namespaceURI); 336 } else { 337 currentElementInfo.put(prefix, namespaceURI); 339 } 340 } else { 341 String uri = currentElementInfo.findNamespaceURI(""); 344 if (StringUtils.isNotEmpty(uri)) { 345 currentElementInfo.put("", ""); 347 } 348 } 349 350 if (namespaceURI == null) 352 namespaceURI = ""; 353 354 String qName; 355 if (StringUtils.isNotEmpty(prefix)) { 356 qName = prefix + ":" + localName; 357 } else { 358 qName = localName; 359 } 360 361 AttributesImpl newAttrs = new AttributesImpl (); 363 for (int i = 0; i < nAttrs; i++) { 364 Node attr = atts.item(i); 365 String attrName = attr.getNodeName(); 366 String assignedAttrPrefix = null; 367 368 if (!(attrName.equals("xmlns") || attrName.startsWith("xmlns:"))) { 370 String attrPrefix; 371 String attrLocalName; 372 String attrNsURI; 373 374 if (attr.getLocalName() == null) { 375 String [] prefixAndLocalName = getPrefixAndLocalName(attrName); 377 attrPrefix = prefixAndLocalName[0]; 378 assignedAttrPrefix = attrPrefix; 381 attrLocalName = prefixAndLocalName[1]; 382 if (attrPrefix != null) 385 attrNsURI = getNamespaceForPrefix(attrPrefix, (Element )node); 386 else 387 attrNsURI = null; 388 } else { 389 attrLocalName = attr.getLocalName(); 390 attrPrefix = attr.getPrefix(); 391 attrNsURI = attr.getNamespaceURI(); 392 } 393 394 if (attrNsURI != null) { 395 String declaredUri = currentElementInfo.findNamespaceURI(attrPrefix); 396 if (declaredUri == null || !declaredUri.equals(attrNsURI)) { 398 String availablePrefix = currentElementInfo.findPrefix(attrNsURI); 399 if (availablePrefix != null && !availablePrefix.equals("")) 400 assignedAttrPrefix = availablePrefix; 401 else { 402 if (attrPrefix != null && declaredUri == null) { 403 assignedAttrPrefix = attrPrefix; 405 currentElementInfo.put(assignedAttrPrefix, attrNsURI); 406 } else { 407 newPrefixCounter++; 410 assignedAttrPrefix = "NS" + newPrefixCounter; 411 currentElementInfo.put(assignedAttrPrefix, attrNsURI); 412 } 413 } 414 } else { 415 assignedAttrPrefix = attrPrefix; 416 } 417 } 418 419 String assignedAttrNsURI = attrNsURI != null ? attrNsURI : ""; 420 String attrQName; 421 if (assignedAttrPrefix != null) { 422 attrQName = assignedAttrPrefix + ":" + attrLocalName; 423 } else { 424 attrQName = attrLocalName; 425 } 426 newAttrs.addAttribute(assignedAttrNsURI, attrLocalName, attrQName, "CDATA", attr.getNodeValue()); 427 } 428 } 429 430 if (currentElementInfo.namespaceDeclarations != null && currentElementInfo.namespaceDeclarations.size() > 0) { 432 Iterator localNsDeclIt = currentElementInfo.namespaceDeclarations.entrySet().iterator(); 433 while (localNsDeclIt.hasNext()) { 434 Map.Entry entry = (Map.Entry ) localNsDeclIt.next(); 435 String pr = (String ) entry.getKey(); 436 String ns = (String ) entry.getValue(); 437 contentHandler.startPrefixMapping(pr, ns); 443 } 444 } 445 446 contentHandler.startElement(namespaceURI, localName, qName, newAttrs); 447 448 currentElementInfo.localName = localName; 449 currentElementInfo.namespaceURI = namespaceURI; 450 currentElementInfo.qName = qName; 451 break; 452 case Node.PROCESSING_INSTRUCTION_NODE: 453 { 454 ProcessingInstruction pi = (ProcessingInstruction ) node; 455 contentHandler.processingInstruction(pi.getNodeName(), pi.getData()); 456 } 457 break; 458 case Node.CDATA_SECTION_NODE: 459 { 460 if (lexicalHandler != null) 461 lexicalHandler.startCDATA(); 462 463 dispatchChars(node); 464 465 if (lexicalHandler != null) 466 lexicalHandler.endCDATA(); 467 } 468 break; 469 case Node.TEXT_NODE: 470 { 471 dispatchChars(node); 472 } 473 break; 474 case Node.ENTITY_REFERENCE_NODE: 475 { 476 EntityReference eref = (EntityReference ) node; 477 478 if (lexicalHandler != null) { 479 lexicalHandler.startEntity(eref.getNodeName()); 480 } else { 481 } 483 } 484 break; 485 default : 486 } 487 } 488 489 506 public String getNamespaceForPrefix(String prefix, Element namespaceContext) { 507 int type; 508 Node parent = namespaceContext; 509 String namespace = null; 510 511 if (prefix == null) 512 prefix = ""; 513 514 if (prefix.equals("xml")) { 515 namespace = "http://www.w3.org/XML/1998/namespace"; 516 } else if(prefix.equals("xmlns")) { 517 namespace = "http://www.w3.org/2000/xmlns/"; 518 } else { 519 String declname = (prefix == "") ? "xmlns" : "xmlns:" + prefix; 521 522 while ((null != parent) && (null == namespace) 524 && (((type = parent.getNodeType()) == Node.ELEMENT_NODE) 525 || (type == Node.ENTITY_REFERENCE_NODE))) { 526 if (type == Node.ELEMENT_NODE) { 527 Attr attr=((Element )parent).getAttributeNode(declname); 528 if (attr != null) { 529 namespace = attr.getNodeValue(); 530 break; 531 } 532 } 533 parent = parent.getParentNode(); 534 } 535 } 536 return namespace; 537 } 538 539 545 private String [] getPrefixAndLocalName(String nodeName) { 546 String prefix, localName; 547 int colonPos = nodeName.indexOf(":"); 548 if (colonPos != -1) { 549 prefix = nodeName.substring(0, colonPos); 550 localName = nodeName.substring(colonPos + 1, nodeName.length()); 551 } else { 552 prefix = null; 553 localName = nodeName; 554 } 555 return new String [] {prefix, localName}; 556 } 557 558 559 564 protected void endNode(Node node) throws org.xml.sax.SAXException { 565 566 switch (node.getNodeType()) { 567 case Node.DOCUMENT_NODE: 568 break; 569 570 case Node.ELEMENT_NODE: 571 contentHandler.endElement(currentElementInfo.namespaceURI, 572 currentElementInfo.localName, currentElementInfo.qName); 573 574 if (currentElementInfo.namespaceDeclarations != null && currentElementInfo.namespaceDeclarations.size() > 0) { 576 Iterator namespaceIt = currentElementInfo.namespaceDeclarations.entrySet().iterator(); 577 while (namespaceIt.hasNext()) { 578 Map.Entry entry = (Map.Entry ) namespaceIt.next(); 579 contentHandler.endPrefixMapping((String ) entry.getKey()); 580 } 582 } 583 584 currentElementInfo = currentElementInfo.parent; 585 break; 586 case Node.CDATA_SECTION_NODE: 587 break; 588 case Node.ENTITY_REFERENCE_NODE: 589 { 590 EntityReference eref = (EntityReference ) node; 591 592 if (lexicalHandler != null) { 593 lexicalHandler.endEntity(eref.getNodeName()); 594 } 595 } 596 break; 597 default : 598 } 599 } 600 601 public static class ElementInfo { 602 public String localName; 603 public String namespaceURI; 604 public String qName; 605 public Map namespaceDeclarations = null; 606 public ElementInfo parent; 607 608 public ElementInfo(ElementInfo parent) { 609 this.parent = parent; 610 } 611 612 616 public void put(String prefix, String namespaceURI) { 617 if (namespaceDeclarations == null) 618 namespaceDeclarations = new HashMap (); 619 namespaceDeclarations.put(prefix, namespaceURI); 620 } 621 622 625 public String getPrefix(String namespaceURI) { 626 if (namespaceDeclarations == null || namespaceDeclarations.size() == 0) 627 return null; 628 Iterator it = namespaceDeclarations.entrySet().iterator(); 631 while (it.hasNext()) { 632 Map.Entry entry = (Map.Entry ) it.next(); 633 if (entry.getValue().equals(namespaceURI)) 634 return (String ) entry.getKey(); 635 } 636 return null; 637 } 638 639 642 public String getNamespaceURI(String prefix) { 643 if (namespaceDeclarations == null || namespaceDeclarations.size() == 0) 644 return null; 645 646 return (String ) namespaceDeclarations.get(prefix); 647 } 648 649 652 public String findPrefix(String namespaceURI) { 653 if (namespaceDeclarations != null && namespaceDeclarations.size() != 0) { 654 String prefix = getPrefix(namespaceURI); 655 if (prefix != null) { 656 return prefix; 657 } 658 } 659 if (parent != null) { 660 return parent.findPrefix(namespaceURI); 661 } else { 662 return null; 663 } 664 } 665 666 669 public String findNamespaceURI(String prefix) { 670 if (namespaceDeclarations != null && namespaceDeclarations.size() != 0) { 671 String uri = (String ) namespaceDeclarations.get(prefix); 672 if (uri != null) { 673 return uri; 674 } 675 } 676 if (parent != null) 677 return parent.findNamespaceURI(prefix); 678 else 679 return null; 680 } 681 } 682 } 683 684 692 public static class DefaultDOMStreamer extends AbstractXMLProducer { 693 694 695 protected Transformer transformer; 696 697 700 public void stream(Node node) 701 throws SAXException { 702 if (this.transformer == null) { 703 try { 704 this.transformer = factory.newTransformer(); 705 } catch (TransformerConfigurationException e) { 706 throw new SAXException (e); 707 } 708 } 709 DOMSource source = new DOMSource (node); 710 711 ContentHandler handler; 712 if (node.getNodeType() == Node.DOCUMENT_NODE) { 713 handler = contentHandler; 715 } else { 716 handler = new EmbeddedXMLPipe(contentHandler); 718 } 719 720 SAXResult result = new SAXResult (handler); 721 result.setLexicalHandler(lexicalHandler); 722 723 try { 724 transformer.transform(source, result); 725 } catch (TransformerException e) { 726 throw new SAXException (e); 727 } 728 } 729 } 730 } 731 | Popular Tags |