Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00
file stats: LOC: 945   Methods: 48
NCLOC: 436   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
SAXWriter.java 65,5% 62,2% 66,7% 63,6%
coverage coverage
 1    /*
 2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 3    *
 4    * This software is open source.
 5    * See the bottom of this file for the licence.
 6    */
 7   
 8    package org.dom4j.io;
 9   
 10    import java.io.IOException;
 11    import java.util.HashMap;
 12    import java.util.Iterator;
 13    import java.util.List;
 14    import java.util.Map;
 15   
 16    import org.dom4j.Attribute;
 17    import org.dom4j.Branch;
 18    import org.dom4j.CDATA;
 19    import org.dom4j.CharacterData;
 20    import org.dom4j.Comment;
 21    import org.dom4j.Document;
 22    import org.dom4j.DocumentType;
 23    import org.dom4j.Element;
 24    import org.dom4j.Entity;
 25    import org.dom4j.Namespace;
 26    import org.dom4j.Node;
 27    import org.dom4j.ProcessingInstruction;
 28    import org.dom4j.Text;
 29    import org.dom4j.tree.NamespaceStack;
 30   
 31    import org.xml.sax.Attributes;
 32    import org.xml.sax.ContentHandler;
 33    import org.xml.sax.DTDHandler;
 34    import org.xml.sax.EntityResolver;
 35    import org.xml.sax.ErrorHandler;
 36    import org.xml.sax.InputSource;
 37    import org.xml.sax.SAXException;
 38    import org.xml.sax.SAXNotRecognizedException;
 39    import org.xml.sax.SAXNotSupportedException;
 40    import org.xml.sax.XMLReader;
 41    import org.xml.sax.ext.LexicalHandler;
 42    import org.xml.sax.helpers.AttributesImpl;
 43    import org.xml.sax.helpers.LocatorImpl;
 44   
 45    /**
 46    * <p>
 47    * <code>SAXWriter</code> writes a DOM4J tree to a SAX ContentHandler.
 48    * </p>
 49    *
 50    * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
 51    * @version $Revision: 1.24 $
 52    */
 53    public class SAXWriter implements XMLReader {
 54    protected static final String[] LEXICAL_HANDLER_NAMES = {
 55    "http://xml.org/sax/properties/lexical-handler",
 56    "http://xml.org/sax/handlers/LexicalHandler" };
 57   
 58    protected static final String FEATURE_NAMESPACE_PREFIXES
 59    = "http://xml.org/sax/features/namespace-prefixes";
 60   
 61    protected static final String FEATURE_NAMESPACES
 62    = "http://xml.org/sax/features/namespaces";
 63   
 64    /** <code>ContentHandler</code> to which SAX events are raised */
 65    private ContentHandler contentHandler;
 66   
 67    /** <code>DTDHandler</code> fired when a document has a DTD */
 68    private DTDHandler dtdHandler;
 69   
 70    /** <code>EntityResolver</code> fired when a document has a DTD */
 71    private EntityResolver entityResolver;
 72   
 73    private ErrorHandler errorHandler;
 74   
 75    /** <code>LexicalHandler</code> fired on Entity and CDATA sections */
 76    private LexicalHandler lexicalHandler;
 77   
 78    /** <code>AttributesImpl</code> used when generating the Attributes */
 79    private AttributesImpl attributes = new AttributesImpl();
 80   
 81    /** Stores the features */
 82    private Map features = new HashMap();
 83   
 84    /** Stores the properties */
 85    private Map properties = new HashMap();
 86   
 87    /** Whether namespace declarations are exported as attributes or not */
 88    private boolean declareNamespaceAttributes;
 89   
 90  20 public SAXWriter() {
 91  20 properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.FALSE);
 92  20 properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.TRUE);
 93    }
 94   
 95  0 public SAXWriter(ContentHandler contentHandler) {
 96  0 this();
 97  0 this.contentHandler = contentHandler;
 98    }
 99   
 100  0 public SAXWriter(ContentHandler contentHandler,
 101    LexicalHandler lexicalHandler) {
 102  0 this();
 103  0 this.contentHandler = contentHandler;
 104  0 this.lexicalHandler = lexicalHandler;
 105    }
 106   
 107  12 public SAXWriter(ContentHandler contentHandler,
 108    LexicalHandler lexicalHandler, EntityResolver entityResolver) {
 109  12 this();
 110  12 this.contentHandler = contentHandler;
 111  12 this.lexicalHandler = lexicalHandler;
 112  12 this.entityResolver = entityResolver;
 113    }
 114   
 115    /**
 116    * A polymorphic method to write any Node to this SAX stream
 117    *
 118    * @param node
 119    * DOCUMENT ME!
 120    *
 121    * @throws SAXException
 122    * DOCUMENT ME!
 123    */
 124  39 public void write(Node node) throws SAXException {
 125  39 int nodeType = node.getNodeType();
 126   
 127  39 switch (nodeType) {
 128  0 case Node.ELEMENT_NODE:
 129  0 write((Element) node);
 130   
 131  0 break;
 132   
 133  0 case Node.ATTRIBUTE_NODE:
 134  0 write((Attribute) node);
 135   
 136  0 break;
 137   
 138  0 case Node.TEXT_NODE:
 139  0 write(node.getText());
 140   
 141  0 break;
 142   
 143  0 case Node.CDATA_SECTION_NODE:
 144  0 write((CDATA) node);
 145   
 146  0 break;
 147   
 148  0 case Node.ENTITY_REFERENCE_NODE:
 149  0 write((Entity) node);
 150   
 151  0 break;
 152   
 153  0 case Node.PROCESSING_INSTRUCTION_NODE:
 154  0 write((ProcessingInstruction) node);
 155   
 156  0 break;
 157   
 158  0 case Node.COMMENT_NODE:
 159  0 write((Comment) node);
 160   
 161  0 break;
 162   
 163  0 case Node.DOCUMENT_NODE:
 164  0 write((Document) node);
 165   
 166  0 break;
 167   
 168  0 case Node.DOCUMENT_TYPE_NODE:
 169  0 write((DocumentType) node);
 170   
 171  0 break;
 172   
 173  39 case Node.NAMESPACE_NODE:
 174   
 175    // Will be output with attributes
 176    // write((Namespace) node);
 177  39 break;
 178   
 179  0 default:
 180  0 throw new SAXException("Invalid node type: " + node);
 181    }
 182    }
 183   
 184    /**
 185    * Generates SAX events for the given Document and all its content
 186    *
 187    * @param document
 188    * is the Document to parse
 189    *
 190    * @throws SAXException
 191    * if there is a SAX error processing the events
 192    */
 193  20 public void write(Document document) throws SAXException {
 194  20 if (document != null) {
 195  20 checkForNullHandlers();
 196   
 197  20 documentLocator(document);
 198  20 startDocument();
 199  20 entityResolver(document);
 200  20 dtdHandler(document);
 201   
 202  20 writeContent(document, new NamespaceStack());
 203  20 endDocument();
 204    }
 205    }
 206   
 207    /**
 208    * Generates SAX events for the given Element and all its content
 209    *
 210    * @param element
 211    * is the Element to parse
 212    *
 213    * @throws SAXException
 214    * if there is a SAX error processing the events
 215    */
 216  0 public void write(Element element) throws SAXException {
 217  0 write(element, new NamespaceStack());
 218    }
 219   
 220    /**
 221    * <p>
 222    * Writes the opening tag of an {@link Element}, including its {@link
 223    * Attribute}s but without its content.
 224    * </p>
 225    *
 226    * @param element
 227    * <code>Element</code> to output.
 228    *
 229    * @throws SAXException
 230    * DOCUMENT ME!
 231    */
 232  0 public void writeOpen(Element element) throws SAXException {
 233  0 startElement(element, null);
 234    }
 235   
 236    /**
 237    * <p>
 238    * Writes the closing tag of an {@link Element}
 239    * </p>
 240    *
 241    * @param element
 242    * <code>Element</code> to output.
 243    *
 244    * @throws SAXException
 245    * DOCUMENT ME!
 246    */
 247  0 public void writeClose(Element element) throws SAXException {
 248  0 endElement(element);
 249    }
 250   
 251    /**
 252    * Generates SAX events for the given text
 253    *
 254    * @param text
 255    * is the text to send to the SAX ContentHandler
 256    *
 257    * @throws SAXException
 258    * if there is a SAX error processing the events
 259    */
 260  12162 public void write(String text) throws SAXException {
 261  12162 if (text != null) {
 262  12162 char[] chars = text.toCharArray();
 263  12162 contentHandler.characters(chars, 0, chars.length);
 264    }
 265    }
 266   
 267    /**
 268    * Generates SAX events for the given CDATA
 269    *
 270    * @param cdata
 271    * is the CDATA to parse
 272    *
 273    * @throws SAXException
 274    * if there is a SAX error processing the events
 275    */
 276  30 public void write(CDATA cdata) throws SAXException {
 277  30 String text = cdata.getText();
 278   
 279  30 if (lexicalHandler != null) {
 280  30 lexicalHandler.startCDATA();
 281  30 write(text);
 282  30 lexicalHandler.endCDATA();
 283    } else {
 284  0 write(text);
 285    }
 286    }
 287   
 288    /**
 289    * Generates SAX events for the given Comment
 290    *
 291    * @param comment
 292    * is the Comment to parse
 293    *
 294    * @throws SAXException
 295    * if there is a SAX error processing the events
 296    */
 297  71 public void write(Comment comment) throws SAXException {
 298  71 if (lexicalHandler != null) {
 299  71 String text = comment.getText();
 300  71 char[] chars = text.toCharArray();
 301  71 lexicalHandler.comment(chars, 0, chars.length);
 302    }
 303    }
 304   
 305    /**
 306    * Generates SAX events for the given Entity
 307    *
 308    * @param entity
 309    * is the Entity to parse
 310    *
 311    * @throws SAXException
 312    * if there is a SAX error processing the events
 313    */
 314  0 public void write(Entity entity) throws SAXException {
 315  0 String text = entity.getText();
 316   
 317  0 if (lexicalHandler != null) {
 318  0 String name = entity.getName();
 319  0 lexicalHandler.startEntity(name);
 320  0 write(text);
 321  0 lexicalHandler.endEntity(name);
 322    } else {
 323  0 write(text);
 324    }
 325    }
 326   
 327    /**
 328    * Generates SAX events for the given ProcessingInstruction
 329    *
 330    * @param pi
 331    * is the ProcessingInstruction to parse
 332    *
 333    * @throws SAXException
 334    * if there is a SAX error processing the events
 335    */
 336  2 public void write(ProcessingInstruction pi) throws SAXException {
 337  2 String target = pi.getTarget();
 338  2 String text = pi.getText();
 339  2 contentHandler.processingInstruction(target, text);
 340    }
 341   
 342    /**
 343    * Should namespace declarations be converted to "xmlns" attributes. This
 344    * property defaults to <code>false</code> as per the SAX specification.
 345    * This property is set via the SAX feature
 346    * "http://xml.org/sax/features/namespace-prefixes"
 347    *
 348    * @return DOCUMENT ME!
 349    */
 350  0 public boolean isDeclareNamespaceAttributes() {
 351  0 return declareNamespaceAttributes;
 352    }
 353   
 354    /**
 355    * Sets whether namespace declarations should be exported as "xmlns"
 356    * attributes or not. This property is set from the SAX feature
 357    * "http://xml.org/sax/features/namespace-prefixes"
 358    *
 359    * @param declareNamespaceAttrs
 360    * DOCUMENT ME!
 361    */
 362  8 public void setDeclareNamespaceAttributes(boolean declareNamespaceAttrs) {
 363  8 this.declareNamespaceAttributes = declareNamespaceAttrs;
 364    }
 365   
 366    // XMLReader methods
 367    // -------------------------------------------------------------------------
 368   
 369    /**
 370    * DOCUMENT ME!
 371    *
 372    * @return the <code>ContentHandler</code> called when SAX events are
 373    * raised
 374    */
 375  0 public ContentHandler getContentHandler() {
 376  0 return contentHandler;
 377    }
 378   
 379    /**
 380    * Sets the <code>ContentHandler</code> called when SAX events are raised
 381    *
 382    * @param contentHandler
 383    * is the <code>ContentHandler</code> called when SAX events
 384    * are raised
 385    */
 386  8 public void setContentHandler(ContentHandler contentHandler) {
 387  8 this.contentHandler = contentHandler;
 388    }
 389   
 390    /**
 391    * DOCUMENT ME!
 392    *
 393    * @return the <code>DTDHandler</code>
 394    */
 395  0 public DTDHandler getDTDHandler() {
 396  0 return dtdHandler;
 397    }
 398   
 399    /**
 400    * Sets the <code>DTDHandler</code>.
 401    *
 402    * @param handler
 403    * DOCUMENT ME!
 404    */
 405  8 public void setDTDHandler(DTDHandler handler) {
 406  8 this.dtdHandler = handler;
 407    }
 408   
 409    /**
 410    * DOCUMENT ME!
 411    *
 412    * @return the <code>ErrorHandler</code>
 413    */
 414  1 public ErrorHandler getErrorHandler() {
 415  1 return errorHandler;
 416    }
 417   
 418    /**
 419    * Sets the <code>ErrorHandler</code>.
 420    *
 421    * @param errorHandler
 422    * DOCUMENT ME!
 423    */
 424  1 public void setErrorHandler(ErrorHandler errorHandler) {
 425  1 this.errorHandler = errorHandler;
 426    }
 427   
 428    /**
 429    * DOCUMENT ME!
 430    *
 431    * @return the <code>EntityResolver</code> used when a Document contains a
 432    * DTD
 433    */
 434  0 public EntityResolver getEntityResolver() {
 435  0 return entityResolver;
 436    }
 437   
 438    /**
 439    * Sets the <code>EntityResolver</code>.
 440    *
 441    * @param entityResolver
 442    * is the <code>EntityResolver</code>
 443    */
 444  0 public void setEntityResolver(EntityResolver entityResolver) {
 445  0 this.entityResolver = entityResolver;
 446    }
 447   
 448    /**
 449    * DOCUMENT ME!
 450    *
 451    * @return the <code>LexicalHandler</code> used when a Document contains a
 452    * DTD
 453    */
 454  0 public LexicalHandler getLexicalHandler() {
 455  0 return lexicalHandler;
 456    }
 457   
 458    /**
 459    * Sets the <code>LexicalHandler</code>.
 460    *
 461    * @param lexicalHandler
 462    * is the <code>LexicalHandler</code>
 463    */
 464  15 public void setLexicalHandler(LexicalHandler lexicalHandler) {
 465  15 this.lexicalHandler = lexicalHandler;
 466    }
 467   
 468    /**
 469    * Sets the <code>XMLReader</code> used to write SAX events to
 470    *
 471    * @param xmlReader
 472    * is the <code>XMLReader</code>
 473    */
 474  0 public void setXMLReader(XMLReader xmlReader) {
 475  0 setContentHandler(xmlReader.getContentHandler());
 476  0 setDTDHandler(xmlReader.getDTDHandler());
 477  0 setEntityResolver(xmlReader.getEntityResolver());
 478  0 setErrorHandler(xmlReader.getErrorHandler());
 479    }
 480   
 481    /**
 482    * Looks up the value of a feature.
 483    *
 484    * @param name
 485    * DOCUMENT ME!
 486    *
 487    * @return DOCUMENT ME!
 488    *
 489    * @throws SAXNotRecognizedException
 490    * DOCUMENT ME!
 491    * @throws SAXNotSupportedException
 492    * DOCUMENT ME!
 493    */
 494  0 public boolean getFeature(String name) throws SAXNotRecognizedException,
 495    SAXNotSupportedException {
 496  0 Boolean answer = (Boolean) features.get(name);
 497   
 498  0 return (answer != null) && answer.booleanValue();
 499    }
 500   
 501    /**
 502    * This implementation does actually use any features but just stores them
 503    * for later retrieval
 504    *
 505    * @param name
 506    * DOCUMENT ME!
 507    * @param value
 508    * DOCUMENT ME!
 509    *
 510    * @throws SAXNotRecognizedException
 511    * DOCUMENT ME!
 512    * @throws SAXNotSupportedException
 513    * DOCUMENT ME!
 514    */
 515  8 public void setFeature(String name, boolean value)
 516    throws SAXNotRecognizedException, SAXNotSupportedException {
 517  8 if (FEATURE_NAMESPACE_PREFIXES.equals(name)) {
 518  8 setDeclareNamespaceAttributes(value);
 519  0 } else if (FEATURE_NAMESPACE_PREFIXES.equals(name)) {
 520  0 if (!value) {
 521  0 String msg = "Namespace feature is always supported in dom4j";
 522  0 throw new SAXNotSupportedException(msg);
 523    }
 524    }
 525   
 526  8 features.put(name, (value) ? Boolean.TRUE : Boolean.FALSE);
 527    }
 528   
 529    /**
 530    * Sets the given SAX property
 531    *
 532    * @param name
 533    * DOCUMENT ME!
 534    * @param value
 535    * DOCUMENT ME!
 536    */
 537  29 public void setProperty(String name, Object value) {
 538  29 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
 539  50 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
 540  15 setLexicalHandler((LexicalHandler) value);
 541   
 542  15 return;
 543    }
 544    }
 545   
 546  14 properties.put(name, value);
 547    }
 548   
 549    /**
 550    * Gets the given SAX property
 551    *
 552    * @param name
 553    * DOCUMENT ME!
 554    *
 555    * @return DOCUMENT ME!
 556    *
 557    * @throws SAXNotRecognizedException
 558    * DOCUMENT ME!
 559    * @throws SAXNotSupportedException
 560    * DOCUMENT ME!
 561    */
 562  0 public Object getProperty(String name) throws SAXNotRecognizedException,
 563    SAXNotSupportedException {
 564  0 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
 565  0 if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
 566  0 return getLexicalHandler();
 567    }
 568    }
 569   
 570  0 return properties.get(name);
 571    }
 572   
 573    /**
 574    * This method is not supported.
 575    *
 576    * @param systemId
 577    * DOCUMENT ME!
 578    *
 579    * @throws SAXNotSupportedException
 580    * DOCUMENT ME!
 581    */
 582  0 public void parse(String systemId) throws SAXNotSupportedException {
 583  0 throw new SAXNotSupportedException("This XMLReader can only accept"
 584    + " <dom4j> InputSource objects");
 585    }
 586   
 587    /**
 588    * Parses an XML document. This method can only accept DocumentInputSource
 589    * inputs otherwise a {@link SAXNotSupportedException}exception is thrown.
 590    *
 591    * @param input
 592    * DOCUMENT ME!
 593    *
 594    * @throws SAXException
 595    * DOCUMENT ME!
 596    * @throws SAXNotSupportedException
 597    * if the input source is not wrapping a dom4j document
 598    */
 599  8 public void parse(InputSource input) throws SAXException {
 600  8 if (input instanceof DocumentInputSource) {
 601  8 DocumentInputSource documentInput = (DocumentInputSource) input;
 602  8 Document document = documentInput.getDocument();
 603  8 write(document);
 604    } else {
 605  0 throw new SAXNotSupportedException(
 606    "This XMLReader can only accept "
 607    + "<dom4j> InputSource objects");
 608    }
 609    }
 610   
 611    // Implementation methods
 612    // -------------------------------------------------------------------------
 613  4973 protected void writeContent(Branch branch, NamespaceStack namespaceStack)
 614    throws SAXException {
 615  4973 for (Iterator iter = branch.nodeIterator(); iter.hasNext();) {
 616  17227 Object object = iter.next();
 617   
 618  17227 if (object instanceof Element) {
 619  4953 write((Element) object, namespaceStack);
 620  12274 } else if (object instanceof CharacterData) {
 621  12233 if (object instanceof Text) {
 622  12132 Text text = (Text) object;
 623  12132 write(text.getText());
 624  101 } else if (object instanceof CDATA) {
 625  30 write((CDATA) object);
 626  71 } else if (object instanceof Comment) {
 627  71 write((Comment) object);
 628    } else {
 629  0 throw new SAXException("Invalid Node in DOM4J content: "
 630    + object + " of type: " + object.getClass());
 631    }
 632  41 } else if (object instanceof String) {
 633  0 write((String) object);
 634  41 } else if (object instanceof Entity) {
 635  0 write((Entity) object);
 636  41 } else if (object instanceof ProcessingInstruction) {
 637  2 write((ProcessingInstruction) object);
 638  39 } else if (object instanceof Namespace) {
 639  39 write((Namespace) object);
 640    } else {
 641  0 throw new SAXException("Invalid Node in DOM4J content: "
 642    + object);
 643    }
 644    }
 645    }
 646   
 647    /**
 648    * The {@link org.xml.sax.Locator}is only really useful when parsing a
 649    * textual document as its main purpose is to identify the line and column
 650    * number. Since we are processing an in memory tree which will probably
 651    * have its line number information removed, we'll just use -1 for the line
 652    * and column numbers.
 653    *
 654    * @param document
 655    * DOCUMENT ME!
 656    *
 657    * @throws SAXException
 658    * DOCUMENT ME!
 659    */
 660  20 protected void documentLocator(Document document) throws SAXException {
 661  20 LocatorImpl locator = new LocatorImpl();
 662   
 663  20 String publicID = null;
 664  20 String systemID = null;
 665  20 DocumentType docType = document.getDocType();
 666   
 667  20 if (docType != null) {
 668  0 publicID = docType.getPublicID();
 669  0 systemID = docType.getSystemID();
 670    }
 671   
 672  20 if (publicID != null) {
 673  0 locator.setPublicId(publicID);
 674    }
 675   
 676  20 if (systemID != null) {
 677  0 locator.setSystemId(systemID);
 678    }
 679   
 680  20 locator.setLineNumber(-1);
 681  20 locator.setColumnNumber(-1);
 682   
 683  20 contentHandler.setDocumentLocator(locator);
 684    }
 685   
 686  20 protected void entityResolver(Document document) throws SAXException {
 687  20 if (entityResolver != null) {
 688  12 DocumentType docType = document.getDocType();
 689   
 690  12 if (docType != null) {
 691  0 String publicID = docType.getPublicID();
 692  0 String systemID = docType.getSystemID();
 693   
 694  0 if ((publicID != null) || (systemID != null)) {
 695  0 try {
 696  0 entityResolver.resolveEntity(publicID, systemID);
 697    } catch (IOException e) {
 698  0 throw new SAXException("Could not resolve publicID: "
 699    + publicID + " systemID: " + systemID, e);
 700    }
 701    }
 702    }
 703    }
 704    }
 705   
 706    /**
 707    * We do not yet support DTD or XML Schemas so this method does nothing
 708    * right now.
 709    *
 710    * @param document
 711    * DOCUMENT ME!
 712    *
 713    * @throws SAXException
 714    * DOCUMENT ME!
 715    */
 716  20 protected void dtdHandler(Document document) throws SAXException {
 717    }
 718   
 719  20 protected void startDocument() throws SAXException {
 720  20 contentHandler.startDocument();
 721    }
 722   
 723  20 protected void endDocument() throws SAXException {
 724  20 contentHandler.endDocument();
 725    }
 726   
 727  4953 protected void write(Element element, NamespaceStack namespaceStack)
 728    throws SAXException {
 729  4953 int stackSize = namespaceStack.size();
 730  4953 AttributesImpl namespaceAttributes = startPrefixMapping(element,
 731    namespaceStack);
 732  4953 startElement(element, namespaceAttributes);
 733  4953 writeContent(element, namespaceStack);
 734  4953 endElement(element);
 735  4953 endPrefixMapping(namespaceStack, stackSize);
 736    }
 737   
 738    /**
 739    * Fires a SAX startPrefixMapping event for all the namespaceStack which
 740    * have just come into scope
 741    *
 742    * @param element
 743    * DOCUMENT ME!
 744    * @param namespaceStack
 745    * DOCUMENT ME!
 746    *
 747    * @return DOCUMENT ME!
 748    *
 749    * @throws SAXException
 750    * DOCUMENT ME!
 751    */
 752  4953 protected AttributesImpl startPrefixMapping(Element element,
 753    NamespaceStack namespaceStack) throws SAXException {
 754  4953 AttributesImpl namespaceAttributes = null;
 755   
 756    // start with the namespace of the element
 757  4953 Namespace elementNamespace = element.getNamespace();
 758   
 759  4953 if ((elementNamespace != null)
 760    && !isIgnoreableNamespace(elementNamespace, namespaceStack)) {
 761  36 namespaceStack.push(elementNamespace);
 762  36 contentHandler.startPrefixMapping(elementNamespace.getPrefix(),
 763    elementNamespace.getURI());
 764  36 namespaceAttributes = addNamespaceAttribute(namespaceAttributes,
 765    elementNamespace);
 766    }
 767   
 768  4953 List declaredNamespaces = element.declaredNamespaces();
 769   
 770  4953 for (int i = 0, size = declaredNamespaces.size(); i < size; i++) {
 771  39 Namespace namespace = (Namespace) declaredNamespaces.get(i);
 772   
 773  39 if (!isIgnoreableNamespace(namespace, namespaceStack)) {
 774  3 namespaceStack.push(namespace);
 775  3 contentHandler.startPrefixMapping(namespace.getPrefix(),
 776    namespace.getURI());
 777  3 namespaceAttributes = addNamespaceAttribute(
 778    namespaceAttributes, namespace);
 779    }
 780    }
 781   
 782  4953 return namespaceAttributes;
 783    }
 784   
 785    /**
 786    * Fires a SAX endPrefixMapping event for all the namespaceStack which have
 787    * gone out of scope
 788    *
 789    * @param stack
 790    * DOCUMENT ME!
 791    * @param stackSize
 792    * DOCUMENT ME!
 793    *
 794    * @throws SAXException
 795    * DOCUMENT ME!
 796    */
 797  4953 protected void endPrefixMapping(NamespaceStack stack, int stackSize)
 798    throws SAXException {
 799  4953 while (stack.size() > stackSize) {
 800  39 Namespace namespace = stack.pop();
 801   
 802  39 if (namespace != null) {
 803  39 contentHandler.endPrefixMapping(namespace.getPrefix());
 804    }
 805    }
 806    }
 807   
 808  4953 protected void startElement(Element element,
 809    AttributesImpl namespaceAttributes) throws SAXException {
 810  4953 contentHandler.startElement(element.getNamespaceURI(), element
 811    .getName(), element.getQualifiedName(), createAttributes(
 812    element, namespaceAttributes));
 813    }
 814   
 815  4953 protected void endElement(Element element) throws SAXException {
 816  4953 contentHandler.endElement(element.getNamespaceURI(), element.getName(),
 817    element.getQualifiedName());
 818    }
 819   
 820  4953 protected Attributes createAttributes(Element element,
 821    Attributes namespaceAttributes) throws SAXException {
 822  4953 attributes.clear();
 823   
 824  4953 if (namespaceAttributes != null) {
 825  12 attributes.setAttributes(namespaceAttributes);
 826    }
 827   
 828  4953 for (Iterator iter = element.attributeIterator(); iter.hasNext();) {
 829  2609 Attribute attribute = (Attribute) iter.next();
 830  2609 attributes.addAttribute(attribute.getNamespaceURI(), attribute
 831    .getName(), attribute.getQualifiedName(), "CDATA",
 832    attribute.getValue());
 833    }
 834   
 835  4953 return attributes;
 836    }
 837   
 838    /**
 839    * If isDelcareNamespaceAttributes() is enabled then this method will add
 840    * the given namespace declaration to the supplied attributes object,
 841    * creating one if it does not exist.
 842    *
 843    * @param attrs
 844    * DOCUMENT ME!
 845    * @param namespace
 846    * DOCUMENT ME!
 847    *
 848    * @return DOCUMENT ME!
 849    */
 850  39 protected AttributesImpl addNamespaceAttribute(AttributesImpl attrs,
 851    Namespace namespace) {
 852  39 if (declareNamespaceAttributes) {
 853  13 if (attrs == null) {
 854  12 attrs = new AttributesImpl();
 855    }
 856   
 857  13 String prefix = namespace.getPrefix();
 858  13 String qualifiedName = "xmlns";
 859   
 860  13 if ((prefix != null) && (prefix.length() > 0)) {
 861  8 qualifiedName = "xmlns:" + prefix;
 862    }
 863   
 864  13 String uri = "";
 865  13 String localName = prefix;
 866  13 String type = "CDATA";
 867  13 String value = namespace.getURI();
 868   
 869  13 attrs.addAttribute(uri, localName, qualifiedName, type, value);
 870    }
 871   
 872  39 return attrs;
 873    }
 874   
 875    /**
 876    * DOCUMENT ME!
 877    *
 878    * @param namespace
 879    * DOCUMENT ME!
 880    * @param namespaceStack
 881    * DOCUMENT ME!
 882    *
 883    * @return true if the given namespace is an ignorable namespace (such as
 884    * Namespace.NO_NAMESPACE or Namespace.XML_NAMESPACE) or if the
 885    * namespace has already been declared in the current scope
 886    */
 887  4992 protected boolean isIgnoreableNamespace(Namespace namespace,
 888    NamespaceStack namespaceStack) {
 889  4992 if (namespace.equals(Namespace.NO_NAMESPACE)
 890    || namespace.equals(Namespace.XML_NAMESPACE)) {
 891  4761 return true;
 892    }
 893   
 894  231 String uri = namespace.getURI();
 895   
 896  231 if ((uri == null) || (uri.length() <= 0)) {
 897  0 return true;
 898    }
 899   
 900  231 return namespaceStack.contains(namespace);
 901    }
 902   
 903    /**
 904    * Ensures non-null content handlers?
 905    */
 906  20 protected void checkForNullHandlers() {
 907    }
 908    }
 909   
 910    /*
 911    * Redistribution and use of this software and associated documentation
 912    * ("Software"), with or without modification, are permitted provided that the
 913    * following conditions are met:
 914    *
 915    * 1. Redistributions of source code must retain copyright statements and
 916    * notices. Redistributions must also contain a copy of this document.
 917    *
 918    * 2. Redistributions in binary form must reproduce the above copyright notice,
 919    * this list of conditions and the following disclaimer in the documentation
 920    * and/or other materials provided with the distribution.
 921    *
 922    * 3. The name "DOM4J" must not be used to endorse or promote products derived
 923    * from this Software without prior written permission of MetaStuff, Ltd. For
 924    * written permission, please contact dom4j-info@metastuff.com.
 925    *
 926    * 4. Products derived from this Software may not be called "DOM4J" nor may
 927    * "DOM4J" appear in their names without prior written permission of MetaStuff,
 928    * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
 929    *
 930    * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
 931    *
 932    * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
 933    * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 934    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 935    * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
 936    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 937    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 938    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 939    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 940    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 941    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 942    * POSSIBILITY OF SUCH DAMAGE.
 943    *
 944    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 945    */