1 /*
   2  * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.stream.writers;
  27 
  28 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
  29 import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
  30 import java.lang.reflect.InvocationTargetException;
  31 import java.lang.reflect.Method;
  32 import javax.xml.XMLConstants;
  33 import javax.xml.namespace.NamespaceContext;
  34 import javax.xml.stream.XMLStreamException;
  35 import javax.xml.stream.XMLStreamWriter;
  36 import javax.xml.transform.dom.DOMResult;
  37 import org.w3c.dom.Attr;
  38 import org.w3c.dom.CDATASection;
  39 import org.w3c.dom.Comment;
  40 import org.w3c.dom.Document;
  41 import org.w3c.dom.Element;
  42 import org.w3c.dom.EntityReference;
  43 import org.w3c.dom.Node;
  44 import org.w3c.dom.ProcessingInstruction;
  45 import org.w3c.dom.Text;
  46 import org.xml.sax.helpers.NamespaceSupport;
  47 
  48 /**
  49  * This class provides support to build a DOM tree using XMLStreamWriter API's.
  50  * @author K Venugopal
  51  */
  52 
  53 /*
  54  * TODO : -Venu
  55  * Internal NamespaceManagement
  56  * setPrefix
  57  * support for isRepairNamespace property.
  58  * Some Unsupported Methods.
  59  * Change StringBuffer to StringBuilder, when JDK 1.5 will be minimum requirement for SJSXP.
  60  */
  61 
  62 public class XMLDOMWriterImpl implements XMLStreamWriterBase  {
  63 
  64 
  65     private Document ownerDoc = null;
  66     private Node currentNode = null;
  67     private Node node = null;
  68     private NamespaceSupport namespaceContext = null;
  69     private boolean [] needContextPop = null;
  70     private StringBuffer stringBuffer = null;
  71     private int resizeValue = 20;
  72     private int depth = 0;
  73     /**
  74      * Creates a new instance of XMLDOMwriterImpl
  75      * @param result DOMResult object @javax.xml.transform.dom.DOMResult
  76      */
  77     public XMLDOMWriterImpl(DOMResult result) {
  78 
  79         node = result.getNode();
  80         if( node.getNodeType() == Node.DOCUMENT_NODE){
  81             ownerDoc = (Document)node;
  82             currentNode = ownerDoc;
  83         }else{
  84             ownerDoc = node.getOwnerDocument();
  85             currentNode = node;
  86         }
  87         stringBuffer = new StringBuffer();
  88         needContextPop = new boolean[resizeValue];
  89         namespaceContext = new NamespaceSupport();
  90     }
  91 
  92     /**
  93      * This method has no effect when called.
  94      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
  95      */
  96     public void close() throws XMLStreamException {
  97         //no-op
  98     }
  99 
 100     /**
 101      * This method has no effect when called.
 102      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 103      */
 104     public void flush() throws XMLStreamException {
 105         //no-op
 106     }
 107 
 108     /**
 109      * {@inheritDoc}
 110      * @return {@inheritDoc}
 111      */
 112     public javax.xml.namespace.NamespaceContext getNamespaceContext() {
 113         return null;
 114     }
 115 
 116     /**
 117      * {@inheritDoc}
 118      * @param namespaceURI {@inheritDoc}
 119      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 120      * @return {@inheritDoc}
 121      */
 122     public String getPrefix(String namespaceURI) throws XMLStreamException {
 123         String prefix = null;
 124         if(this.namespaceContext != null){
 125             prefix = namespaceContext.getPrefix(namespaceURI);
 126         }
 127         return prefix;
 128     }
 129 
 130     /**
 131      * Is not supported in this implementation.
 132      * @param str {@inheritDoc}
 133      * @throws java.lang.IllegalArgumentException {@inheritDoc}
 134      * @return {@inheritDoc}
 135      */
 136     public Object getProperty(String str) throws IllegalArgumentException {
 137         throw new UnsupportedOperationException();
 138     }
 139 
 140     /**
 141      * Is not supported in this version of the implementation.
 142      * @param uri {@inheritDoc}
 143      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 144      */
 145     public void setDefaultNamespace(String uri) throws XMLStreamException {
 146         namespaceContext.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri);
 147         if(!needContextPop[depth]){
 148             needContextPop[depth] = true;
 149         }
 150     }
 151 
 152     /**
 153      * {@inheritDoc}
 154      * @param namespaceContext {@inheritDoc}
 155      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 156      */
 157     public void setNamespaceContext(javax.xml.namespace.NamespaceContext namespaceContext) throws XMLStreamException {
 158         throw new UnsupportedOperationException();
 159     }
 160 
 161     /**
 162      * Is not supported in this version of the implementation.
 163      * @param prefix {@inheritDoc}
 164      * @param uri {@inheritDoc}
 165      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 166      */
 167     public void setPrefix(String prefix, String uri) throws XMLStreamException {
 168         if(prefix == null){
 169             throw new XMLStreamException("Prefix cannot be null");
 170         }
 171         namespaceContext.declarePrefix(prefix, uri);
 172         if(!needContextPop[depth]){
 173             needContextPop[depth] = true;
 174         }
 175     }
 176 
 177     /**
 178      * Creates a DOM Atrribute @see org.w3c.dom.Node and associates it with the current DOM element @see org.w3c.dom.Node.
 179      * @param localName {@inheritDoc}
 180      * @param value {@inheritDoc}
 181      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 182      */
 183     public void writeAttribute(String localName, String value) throws XMLStreamException {
 184 
 185         if(currentNode.getNodeType() == Node.ELEMENT_NODE){
 186             Attr attr = ownerDoc.createAttribute(localName);
 187             attr.setValue(value);
 188             ((Element)currentNode).setAttributeNode(attr);
 189         }else{
 190             //Convert node type to String
 191             throw new IllegalStateException("Current DOM Node type  is "+ currentNode.getNodeType() +
 192                     "and does not allow attributes to be set ");
 193         }
 194     }
 195 
 196     /**
 197      * Creates a DOM Atrribute @see org.w3c.dom.Node and associates it with the current DOM element @see org.w3c.dom.Node.
 198      * @param namespaceURI {@inheritDoc}
 199      * @param localName {@inheritDoc}
 200      * @param value {@inheritDoc}
 201      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 202      */
 203     public void writeAttribute(String namespaceURI,String localName,String value)throws XMLStreamException {
 204         if(currentNode.getNodeType() == Node.ELEMENT_NODE){
 205             String prefix = null;
 206             if(namespaceURI == null ){
 207                 throw new XMLStreamException("NamespaceURI cannot be null");
 208             }
 209             if(localName == null){
 210                 throw new XMLStreamException("Local name cannot be null");
 211             }
 212             if(namespaceContext != null){
 213                 prefix = namespaceContext.getPrefix(namespaceURI);
 214             }
 215 
 216             if(prefix == null){
 217                 throw new XMLStreamException("Namespace URI "+namespaceURI +
 218                         "is not bound to any prefix" );
 219             }
 220 
 221             String qualifiedName = null;
 222             if(prefix.isEmpty()){
 223                 qualifiedName = localName;
 224             }else{
 225                 qualifiedName = getQName(prefix,localName);
 226             }
 227             Attr attr = ownerDoc.createAttributeNS(namespaceURI, qualifiedName);
 228             attr.setValue(value);
 229             ((Element)currentNode).setAttributeNode(attr);
 230         }else{
 231             //Convert node type to String
 232             throw new IllegalStateException("Current DOM Node type  is "+ currentNode.getNodeType() +
 233                     "and does not allow attributes to be set ");
 234         }
 235     }
 236 
 237     /**
 238      * Creates a DOM Atrribute @see org.w3c.dom.Node and associates it with the current DOM element @see org.w3c.dom.Node.
 239      * @param prefix {@inheritDoc}
 240      * @param namespaceURI {@inheritDoc}
 241      * @param localName {@inheritDoc}
 242      * @param value {@inheritDoc}
 243      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 244      */
 245     public void writeAttribute(String prefix,String namespaceURI,String localName,String value)throws XMLStreamException {
 246         if(currentNode.getNodeType() == Node.ELEMENT_NODE){
 247             if(namespaceURI == null ){
 248                 throw new XMLStreamException("NamespaceURI cannot be null");
 249             }
 250             if(localName == null){
 251                 throw new XMLStreamException("Local name cannot be null");
 252             }
 253             if(prefix == null){
 254                 throw new XMLStreamException("prefix cannot be null");
 255             }
 256             String qualifiedName = null;
 257             if(prefix.isEmpty()){
 258                 qualifiedName = localName;
 259             }else{
 260 
 261                 qualifiedName = getQName(prefix,localName);
 262             }
 263             Attr attr = ownerDoc.createAttributeNS(namespaceURI, qualifiedName);
 264             attr.setValue(value);
 265             ((Element)currentNode).setAttributeNodeNS(attr);
 266         }else{
 267             //Convert node type to String
 268             throw new IllegalStateException("Current DOM Node type  is "+ currentNode.getNodeType() +
 269                     "and does not allow attributes to be set ");
 270         }
 271 
 272     }
 273 
 274     /**
 275      * Creates a CDATA object @see org.w3c.dom.CDATASection.
 276      * @param data {@inheritDoc}
 277      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 278      */
 279     public void writeCData(String data) throws XMLStreamException {
 280         if(data == null){
 281             throw new XMLStreamException("CDATA cannot be null");
 282         }
 283 
 284         CDATASection cdata = ownerDoc.createCDATASection(data);
 285         getNode().appendChild(cdata);
 286     }
 287 
 288     /**
 289      * Creates a character object @see org.w3c.dom.Text and appends it to the current
 290      * element in the DOM tree.
 291      * @param charData {@inheritDoc}
 292      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 293      */
 294     public void writeCharacters(String charData) throws XMLStreamException {
 295         Text text = ownerDoc.createTextNode(charData);
 296         currentNode.appendChild(text);
 297     }
 298 
 299     /**
 300      * Creates a character object @see org.w3c.dom.Text and appends it to the current
 301      * element in the DOM tree.
 302      * @param values {@inheritDoc}
 303      * @param param {@inheritDoc}
 304      * @param param2 {@inheritDoc}
 305      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 306      */
 307     public void writeCharacters(char[] values, int param, int param2) throws XMLStreamException {
 308 
 309         Text text = ownerDoc.createTextNode(new String(values,param,param2));
 310         currentNode.appendChild(text);
 311     }
 312 
 313     /**
 314      * Creates a Comment object @see org.w3c.dom.Comment and appends it to the current
 315      * element in the DOM tree.
 316      * @param str {@inheritDoc}
 317      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 318      */
 319     public void writeComment(String str) throws XMLStreamException {
 320         Comment comment = ownerDoc.createComment(str);
 321         getNode().appendChild(comment);
 322     }
 323 
 324     /**
 325      * This method is not supported in this implementation.
 326      * @param str {@inheritDoc}
 327      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 328      */
 329     public void writeDTD(String str) throws XMLStreamException {
 330         throw new UnsupportedOperationException();
 331     }
 332 
 333     /**
 334      * Creates a DOM attribute and adds it to the current element in the DOM tree.
 335      * @param namespaceURI {@inheritDoc}
 336      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 337      */
 338     public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
 339         if(currentNode.getNodeType() == Node.ELEMENT_NODE){
 340             String qname = XMLConstants.XMLNS_ATTRIBUTE;
 341             ((Element)currentNode).setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,qname, namespaceURI);
 342         }else{
 343             //Convert node type to String
 344             throw new IllegalStateException("Current DOM Node type  is "+ currentNode.getNodeType() +
 345                     "and does not allow attributes to be set ");
 346         }
 347     }
 348 
 349     /**
 350      * creates a DOM Element and appends it to the current element in the tree.
 351      * @param localName {@inheritDoc}
 352      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 353      */
 354     public void writeEmptyElement(String localName) throws XMLStreamException {
 355         if(ownerDoc != null){
 356             Element element = ownerDoc.createElement(localName);
 357             if(currentNode!=null){
 358                 currentNode.appendChild(element);
 359             }else{
 360                 ownerDoc.appendChild(element);
 361             }
 362         }
 363 
 364     }
 365 
 366     /**
 367      * creates a DOM Element and appends it to the current element in the tree.
 368      * @param namespaceURI {@inheritDoc}
 369      * @param localName {@inheritDoc}
 370      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 371      */
 372     public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
 373         if(ownerDoc != null){
 374             String qualifiedName = null;
 375             String prefix = null;
 376             if(namespaceURI == null ){
 377                 throw new XMLStreamException("NamespaceURI cannot be null");
 378             }
 379             if(localName == null){
 380                 throw new XMLStreamException("Local name cannot be null");
 381             }
 382 
 383             if(namespaceContext != null){
 384                 prefix = namespaceContext.getPrefix(namespaceURI);
 385             }
 386             if(prefix == null){
 387                 throw new XMLStreamException("Namespace URI "+namespaceURI +
 388                         "is not bound to any prefix" );
 389             }
 390             if("".equals(prefix)){
 391                 qualifiedName = localName;
 392             }else{
 393 
 394                 qualifiedName = getQName(prefix,localName);
 395 
 396             }
 397             Element element = ownerDoc.createElementNS(namespaceURI, qualifiedName);
 398             if(currentNode!=null){
 399                 currentNode.appendChild(element);
 400             }else{
 401                 ownerDoc.appendChild(element);
 402             }
 403             //currentNode = element;
 404         }
 405     }
 406 
 407     /**
 408      * creates a DOM Element and appends it to the current element in the tree.
 409      * @param prefix {@inheritDoc}
 410      * @param localName {@inheritDoc}
 411      * @param namespaceURI {@inheritDoc}
 412      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 413      */
 414     public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
 415         if(ownerDoc != null){
 416             if(namespaceURI == null ){
 417                 throw new XMLStreamException("NamespaceURI cannot be null");
 418             }
 419             if(localName == null){
 420                 throw new XMLStreamException("Local name cannot be null");
 421             }
 422             if(prefix == null){
 423                 throw new XMLStreamException("Prefix cannot be null");
 424             }
 425             String qualifiedName = null;
 426             if("".equals(prefix)){
 427                 qualifiedName = localName;
 428             }else{
 429                 qualifiedName = getQName(prefix,localName);
 430             }
 431             Element el  = ownerDoc.createElementNS(namespaceURI,qualifiedName);
 432             if(currentNode!=null){
 433                 currentNode.appendChild(el);
 434             }else{
 435                 ownerDoc.appendChild(el);
 436             }
 437 
 438         }
 439     }
 440 
 441     /**
 442      * Will reset current Node pointer maintained by the implementation.
 443      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 444      */
 445     public void writeEndDocument() throws XMLStreamException {
 446         //What do you want me to do eh! :)
 447         currentNode = null;
 448         for(int i=0; i< depth;i++){
 449             if(needContextPop[depth]){
 450                 needContextPop[depth] = false;
 451                 namespaceContext.popContext();
 452             }
 453             depth--;
 454         }
 455         depth =0;
 456     }
 457 
 458     /**
 459      * Internal current Node pointer will point to the parent of the current Node.
 460      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 461      */
 462     public void writeEndElement() throws XMLStreamException {
 463         Node node= currentNode.getParentNode();
 464         if(currentNode.getNodeType() == Node.DOCUMENT_NODE){
 465             currentNode = null;
 466         }else{
 467             currentNode = node;
 468         }
 469         if(needContextPop[depth]){
 470             needContextPop[depth] = false;
 471             namespaceContext.popContext();
 472         }
 473         depth--;
 474     }
 475 
 476     /**
 477      * Is not supported in this implementation.
 478      * @param name {@inheritDoc}
 479      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 480      */
 481     public void writeEntityRef(String name) throws XMLStreamException {
 482         EntityReference er = ownerDoc.createEntityReference(name);
 483         currentNode.appendChild(er);
 484     }
 485 
 486     /**
 487      * creates a namespace attribute and will associate it with the current element in
 488      * the DOM tree.
 489      * @param prefix {@inheritDoc}
 490      * @param namespaceURI {@inheritDoc}
 491      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 492      */
 493     public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
 494 
 495         if (prefix == null) {
 496             throw new XMLStreamException("prefix cannot be null");
 497         }
 498 
 499         if (namespaceURI == null) {
 500             throw new XMLStreamException("NamespaceURI cannot be null");
 501         }
 502 
 503         String qname = null;
 504 
 505         if (prefix.isEmpty()) {
 506             qname = XMLConstants.XMLNS_ATTRIBUTE;
 507         } else {
 508             qname = getQName(XMLConstants.XMLNS_ATTRIBUTE,prefix);
 509         }
 510 
 511         ((Element)currentNode).setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,qname, namespaceURI);
 512     }
 513 
 514     /**
 515      * is not supported in this release.
 516      * @param target {@inheritDoc}
 517      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 518      */
 519     public void writeProcessingInstruction(String target) throws XMLStreamException {
 520         if(target == null){
 521             throw new XMLStreamException("Target cannot be null");
 522         }
 523         ProcessingInstruction pi = ownerDoc.createProcessingInstruction(target, "");
 524         currentNode.appendChild(pi);
 525     }
 526 
 527     /**
 528      * is not supported in this release.
 529      * @param target {@inheritDoc}
 530      * @param data {@inheritDoc}
 531      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 532      */
 533     public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
 534         if(target == null){
 535             throw new XMLStreamException("Target cannot be null");
 536         }
 537         ProcessingInstruction pi  = ownerDoc.createProcessingInstruction(target, data);
 538         currentNode.appendChild(pi);
 539     }
 540 
 541     /**
 542      * will set version on the Document object when the DOM Node passed to this implementation
 543      * supports DOM Level3 API's.
 544      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 545      */
 546     public void writeStartDocument() throws XMLStreamException {
 547         ownerDoc.setXmlVersion("1.0");
 548     }
 549 
 550     /**
 551      * will set version on the Document object when the DOM Node passed to this implementation
 552      * supports DOM Level3 API's.
 553      * @param version {@inheritDoc}
 554      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 555      */
 556     public void writeStartDocument(String version) throws XMLStreamException {
 557         writeStartDocument(null, version, false, false);
 558     }
 559 
 560     /**
 561      * will set version on the Document object when the DOM Node passed to this implementation
 562      * supports DOM Level3 API's.
 563      * @param encoding {@inheritDoc}
 564      * @param version {@inheritDoc}
 565      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 566      */
 567     public void writeStartDocument(String encoding, String version) throws XMLStreamException {
 568         writeStartDocument(encoding, version, false, false);
 569     }
 570 
 571     @Override
 572     public void writeStartDocument(String encoding, String version, boolean standalone, boolean standaloneSet) throws XMLStreamException {
 573         if (encoding != null && ownerDoc.getClass().isAssignableFrom(DocumentImpl.class)) {
 574             ((DocumentImpl)ownerDoc).setXmlEncoding(encoding);
 575         }
 576 
 577         ownerDoc.setXmlVersion(version);
 578 
 579         if (standaloneSet) {
 580             ownerDoc.setXmlStandalone(standalone);
 581         }
 582     }
 583 
 584     /**
 585      * creates a DOM Element and appends it to the current element in the tree.
 586      * @param localName {@inheritDoc}
 587      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 588      */
 589     public void writeStartElement(String localName) throws XMLStreamException {
 590         if(ownerDoc != null){
 591             Element element = ownerDoc.createElement(localName);
 592             if(currentNode!=null){
 593                 currentNode.appendChild(element);
 594             }else{
 595                 ownerDoc.appendChild(element);
 596             }
 597             currentNode = element;
 598         }
 599         if(needContextPop[depth]){
 600             namespaceContext.pushContext();
 601         }
 602         incDepth();
 603     }
 604 
 605     /**
 606      * creates a DOM Element and appends it to the current element in the tree.
 607      * @param namespaceURI {@inheritDoc}
 608      * @param localName {@inheritDoc}
 609      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 610      */
 611     public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
 612         if(ownerDoc != null){
 613             String qualifiedName = null;
 614             String prefix = null;
 615 
 616             if(namespaceURI == null ){
 617                 throw new XMLStreamException("NamespaceURI cannot be null");
 618             }
 619             if(localName == null){
 620                 throw new XMLStreamException("Local name cannot be null");
 621             }
 622 
 623             if(namespaceContext != null){
 624                 prefix = namespaceContext.getPrefix(namespaceURI);
 625             }
 626             if(prefix == null){
 627                 throw new XMLStreamException("Namespace URI "+namespaceURI +
 628                         "is not bound to any prefix" );
 629             }
 630             if("".equals(prefix)){
 631                 qualifiedName = localName;
 632             }else{
 633                 qualifiedName =  getQName(prefix,localName);
 634             }
 635 
 636             Element element = ownerDoc.createElementNS(namespaceURI, qualifiedName);
 637 
 638             if(currentNode!=null){
 639                 currentNode.appendChild(element);
 640             }else{
 641                 ownerDoc.appendChild(element);
 642             }
 643             currentNode = element;
 644         }
 645         if(needContextPop[depth]){
 646             namespaceContext.pushContext();
 647         }
 648         incDepth();
 649     }
 650 
 651     /**
 652      * creates a DOM Element and appends it to the current element in the tree.
 653      * @param prefix {@inheritDoc}
 654      * @param localName {@inheritDoc}
 655      * @param namespaceURI {@inheritDoc}
 656      * @throws javax.xml.stream.XMLStreamException {@inheritDoc}
 657      */
 658     public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
 659 
 660         if(ownerDoc != null){
 661             String qname = null;
 662             if(namespaceURI == null ){
 663                 throw new XMLStreamException("NamespaceURI cannot be null");
 664             }
 665             if(localName == null){
 666                 throw new XMLStreamException("Local name cannot be null");
 667             }
 668             if(prefix == null){
 669                 throw new XMLStreamException("Prefix cannot be null");
 670             }
 671 
 672             if(prefix.isEmpty()){
 673                 qname = localName;
 674             }else{
 675                 qname = getQName(prefix,localName);
 676             }
 677 
 678             Element el = ownerDoc.createElementNS(namespaceURI,qname);
 679 
 680             if(currentNode!=null){
 681                 currentNode.appendChild(el);
 682             }else{
 683                 ownerDoc.appendChild(el);
 684             }
 685             currentNode = el;
 686             if(needContextPop[depth]){
 687                 namespaceContext.pushContext();
 688             }
 689             incDepth();
 690 
 691         }
 692     }
 693 
 694     private String getQName(String prefix , String localName){
 695         stringBuffer.setLength(0);
 696         stringBuffer.append(prefix);
 697         stringBuffer.append(":");
 698         stringBuffer.append(localName);
 699         return stringBuffer.toString();
 700     }
 701 
 702     private Node getNode(){
 703         if(currentNode == null){
 704             return ownerDoc;
 705         } else{
 706             return currentNode;
 707         }
 708     }
 709     private void incDepth() {
 710         depth++;
 711         if (depth == needContextPop.length) {
 712             boolean[] array = new boolean[depth + resizeValue];
 713             System.arraycopy(needContextPop, 0, array, 0, depth);
 714             needContextPop = array;
 715         }
 716     }
 717 }