jaxp/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
changeset 12005 a754d69d5e60
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java	Sun Mar 04 11:55:34 2012 -0800
@@ -0,0 +1,756 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
+ */
+
+package com.sun.org.apache.xalan.internal.xsltc.runtime;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.xml.transform.Templates;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMImplementation;
+import javax.xml.parsers.ParserConfigurationException;
+
+import com.sun.org.apache.xml.internal.dtm.DTM;
+
+import com.sun.org.apache.xalan.internal.xsltc.DOM;
+import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
+import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
+import com.sun.org.apache.xalan.internal.xsltc.Translet;
+import com.sun.org.apache.xalan.internal.xsltc.TransletException;
+import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
+import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
+import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
+import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
+import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
+
+/**
+ * @author Jacek Ambroziak
+ * @author Santiago Pericas-Geertsen
+ * @author Morten Jorgensen
+ * @author G. Todd Miller
+ * @author John Howard, JohnH@schemasoft.com
+ */
+public abstract class AbstractTranslet implements Translet {
+
+    // These attributes are extracted from the xsl:output element. They also
+    // appear as fields (with the same type, only public) in Output.java
+    public String  _version = "1.0";
+    public String  _method = null;
+    public String  _encoding = "UTF-8";
+    public boolean _omitHeader = false;
+    public String  _standalone = null;
+    public String  _doctypePublic = null;
+    public String  _doctypeSystem = null;
+    public boolean _indent = false;
+    public String  _mediaType = null;
+    public Vector _cdata = null;
+    public int _indentamount = -1;
+
+    public static final int FIRST_TRANSLET_VERSION = 100;
+    public static final int VER_SPLIT_NAMES_ARRAY = 101;
+    public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;
+
+    // Initialize Translet version field to base value.  A class that extends
+    // AbstractTranslet may override this value to a more recent translet
+    // version; if it doesn't override the value (because it was compiled
+    // before the notion of a translet version was introduced, it will get
+    // this default value).
+    protected int transletVersion = FIRST_TRANSLET_VERSION;
+
+    // DOM/translet handshaking - the arrays are set by the compiled translet
+    protected String[] namesArray;
+    protected String[] urisArray;
+    protected int[]    typesArray;
+    protected String[] namespaceArray;
+
+    // The Templates object that is used to create this Translet instance
+    protected Templates _templates = null;
+
+    // Boolean flag to indicate whether this translet has id functions.
+    protected boolean _hasIdCall = false;
+
+    // TODO - these should only be instanciated when needed
+    protected StringValueHandler stringValueHandler = new StringValueHandler();
+
+    // Use one empty string instead of constantly instanciating String("");
+    private final static String EMPTYSTRING = "";
+
+    // This is the name of the index used for ID attributes
+    private final static String ID_INDEX_NAME = "##id";
+
+
+    /************************************************************************
+     * Debugging
+     ************************************************************************/
+    public void printInternalState() {
+        System.out.println("-------------------------------------");
+        System.out.println("AbstractTranslet this = " + this);
+        System.out.println("pbase = " + pbase);
+        System.out.println("vframe = " + pframe);
+        System.out.println("paramsStack.size() = " + paramsStack.size());
+        System.out.println("namesArray.size = " + namesArray.length);
+        System.out.println("namespaceArray.size = " + namespaceArray.length);
+        System.out.println("");
+        System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
+    }
+
+    /**
+     * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
+     * a DOM multiplexer if the document() function is used (handled by compiled
+     * code in the translet - see compiler/Stylesheet.compileTransform()).
+     */
+    public final DOMAdapter makeDOMAdapter(DOM dom)
+        throws TransletException {
+        setRootForKeys(dom.getDocument());
+        return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray);
+    }
+
+    /************************************************************************
+     * Parameter handling
+     ************************************************************************/
+
+    // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
+    // to denote the current parameter frame.
+    protected int pbase = 0, pframe = 0;
+    protected ArrayList paramsStack = new ArrayList();
+
+    /**
+     * Push a new parameter frame.
+     */
+    public final void pushParamFrame() {
+        paramsStack.add(pframe, new Integer(pbase));
+        pbase = ++pframe;
+    }
+
+    /**
+     * Pop the topmost parameter frame.
+     */
+    public final void popParamFrame() {
+        if (pbase > 0) {
+            final int oldpbase = ((Integer)paramsStack.get(--pbase)).intValue();
+            for (int i = pframe - 1; i >= pbase; i--) {
+                paramsStack.remove(i);
+            }
+            pframe = pbase; pbase = oldpbase;
+        }
+    }
+
+    /**
+     * Add a new global parameter if not already in the current frame.
+     * To setParameters of the form {http://foo.bar}xyz
+     * This needs to get mapped to an instance variable in the class
+     * The mapping  created so that
+     * the global variables in the generated class become
+     * http$colon$$flash$$flash$foo$dot$bar$colon$xyz
+     */
+    public final Object addParameter(String name, Object value) {
+        name = BasisLibrary.mapQNameToJavaName (name);
+        return addParameter(name, value, false);
+    }
+
+    /**
+     * Add a new global or local parameter if not already in the current frame.
+     * The 'isDefault' parameter is set to true if the value passed is the
+     * default value from the <xsl:parameter> element's select attribute or
+     * element body.
+     */
+    public final Object addParameter(String name, Object value,
+        boolean isDefault)
+    {
+        // Local parameters need to be re-evaluated for each iteration
+        for (int i = pframe - 1; i >= pbase; i--) {
+            final Parameter param = (Parameter) paramsStack.get(i);
+
+            if (param._name.equals(name)) {
+                // Only overwrite if current value is the default value and
+                // the new value is _NOT_ the default value.
+                if (param._isDefault || !isDefault) {
+                    param._value = value;
+                    param._isDefault = isDefault;
+                    return value;
+                }
+                return param._value;
+            }
+        }
+
+        // Add new parameter to parameter stack
+        paramsStack.add(pframe++, new Parameter(name, value, isDefault));
+        return value;
+    }
+
+    /**
+     * Clears the parameter stack.
+     */
+    public void clearParameters() {
+        pbase = pframe = 0;
+        paramsStack.clear();
+    }
+
+    /**
+     * Get the value of a parameter from the current frame or
+     * <tt>null</tt> if undefined.
+     */
+    public final Object getParameter(String name) {
+
+        name = BasisLibrary.mapQNameToJavaName (name);
+
+        for (int i = pframe - 1; i >= pbase; i--) {
+            final Parameter param = (Parameter)paramsStack.get(i);
+            if (param._name.equals(name)) return param._value;
+        }
+        return null;
+    }
+
+    /************************************************************************
+     * Message handling - implementation of <xsl:message>
+     ************************************************************************/
+
+    // Holds the translet's message handler - used for <xsl:message>.
+    // The deault message handler dumps a string stdout, but anything can be
+    // used, such as a dialog box for applets, etc.
+    private MessageHandler _msgHandler = null;
+
+    /**
+     * Set the translet's message handler - must implement MessageHandler
+     */
+    public final void setMessageHandler(MessageHandler handler) {
+        _msgHandler = handler;
+    }
+
+    /**
+     * Pass a message to the message handler - used by Message class.
+     */
+    public final void displayMessage(String msg) {
+        if (_msgHandler == null) {
+            System.err.println(msg);
+        }
+        else {
+            _msgHandler.displayMessage(msg);
+        }
+    }
+
+    /************************************************************************
+     * Decimal number format symbol handling
+     ************************************************************************/
+
+    // Contains decimal number formatting symbols used by FormatNumberCall
+    public Hashtable _formatSymbols = null;
+
+    /**
+     * Adds a DecimalFormat object to the _formatSymbols hashtable.
+     * The entry is created with the input DecimalFormatSymbols.
+     */
+    public void addDecimalFormat(String name, DecimalFormatSymbols symbols) {
+        // Instanciate hashtable for formatting symbols if needed
+        if (_formatSymbols == null) _formatSymbols = new Hashtable();
+
+        // The name cannot be null - use empty string instead
+        if (name == null) name = EMPTYSTRING;
+
+        // Construct a DecimalFormat object containing the symbols we got
+        final DecimalFormat df = new DecimalFormat();
+        if (symbols != null) {
+            df.setDecimalFormatSymbols(symbols);
+        }
+        _formatSymbols.put(name, df);
+    }
+
+    /**
+     * Retrieves a named DecimalFormat object from _formatSymbols hashtable.
+     */
+    public final DecimalFormat getDecimalFormat(String name) {
+
+        if (_formatSymbols != null) {
+            // The name cannot be null - use empty string instead
+            if (name == null) name = EMPTYSTRING;
+
+            DecimalFormat df = (DecimalFormat)_formatSymbols.get(name);
+            if (df == null) df = (DecimalFormat)_formatSymbols.get(EMPTYSTRING);
+            return df;
+        }
+        return(null);
+    }
+
+    /**
+     * Give the translet an opportunity to perform a prepass on the document
+     * to extract any information that it can store in an optimized form.
+     *
+     * Currently, it only extracts information about attributes of type ID.
+     */
+    public final void prepassDocument(DOM document) {
+        setIndexSize(document.getSize());
+        buildIDIndex(document);
+    }
+
+    /**
+     * Leverages the Key Class to implement the XSLT id() function.
+     * buildIdIndex creates the index (##id) that Key Class uses.
+     * The index contains the element node index (int) and Id value (String).
+     */
+    private final void buildIDIndex(DOM document) {
+        setRootForKeys(document.getDocument());
+
+        if (document instanceof DOMEnhancedForDTM) {
+            DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document;
+
+            // If the input source is DOMSource, the KeyIndex table is not
+            // built at this time. It will be built later by the lookupId()
+            // and containsId() methods of the KeyIndex class.
+            if (enhancedDOM.hasDOMSource()) {
+                buildKeyIndex(ID_INDEX_NAME, document);
+                return;
+            }
+            else {
+                final Hashtable elementsByID = enhancedDOM.getElementsWithIDs();
+
+                if (elementsByID == null) {
+                    return;
+                }
+
+                // Given a Hashtable of DTM nodes indexed by ID attribute values,
+                // loop through the table copying information to a KeyIndex
+                // for the mapping from ID attribute value to DTM node
+                final Enumeration idValues = elementsByID.keys();
+                boolean hasIDValues = false;
+
+                while (idValues.hasMoreElements()) {
+                    final Object idValue = idValues.nextElement();
+                    final int element =
+                            document.getNodeHandle(
+                                        ((Integer)elementsByID.get(idValue))
+                                                .intValue());
+
+                    buildKeyIndex(ID_INDEX_NAME, element, idValue);
+                    hasIDValues = true;
+                }
+
+                if (hasIDValues) {
+                    setKeyIndexDom(ID_INDEX_NAME, document);
+                }
+            }
+        }
+    }
+
+    /**
+     * After constructing the translet object, this method must be called to
+     * perform any version-specific post-initialization that's required.
+     */
+    public final void postInitialization() {
+        // If the version of the translet had just one namesArray, split
+        // it into multiple fields.
+        if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
+            int arraySize = namesArray.length;
+            String[] newURIsArray = new String[arraySize];
+            String[] newNamesArray = new String[arraySize];
+            int[] newTypesArray = new int[arraySize];
+
+            for (int i = 0; i < arraySize; i++) {
+                String name = namesArray[i];
+                int colonIndex = name.lastIndexOf(':');
+                int lNameStartIdx = colonIndex+1;
+
+                if (colonIndex > -1) {
+                    newURIsArray[i] = name.substring(0, colonIndex);
+                }
+
+               // Distinguish attribute and element names.  Attribute has
+               // @ before local part of name.
+               if (name.charAt(lNameStartIdx) == '@') {
+                   lNameStartIdx++;
+                   newTypesArray[i] = DTM.ATTRIBUTE_NODE;
+               } else if (name.charAt(lNameStartIdx) == '?') {
+                   lNameStartIdx++;
+                   newTypesArray[i] = DTM.NAMESPACE_NODE;
+               } else {
+                   newTypesArray[i] = DTM.ELEMENT_NODE;
+               }
+               newNamesArray[i] =
+                          (lNameStartIdx == 0) ? name
+                                               : name.substring(lNameStartIdx);
+            }
+
+            namesArray = newNamesArray;
+            urisArray  = newURIsArray;
+            typesArray = newTypesArray;
+        }
+
+        // Was translet compiled using a more recent version of the XSLTC
+        // compiler than is known by the AbstractTranslet class?  If, so
+        // and we've made it this far (which is doubtful), we should give up.
+        if (transletVersion > CURRENT_TRANSLET_VERSION) {
+            BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
+                                      this.getClass().getName());
+        }
+    }
+
+    /************************************************************************
+     * Index(es) for <xsl:key> / key() / id()
+     ************************************************************************/
+
+    // Container for all indexes for xsl:key elements
+    private Hashtable _keyIndexes = null;
+    private KeyIndex  _emptyKeyIndex = null;
+    private int       _indexSize = 0;
+    private int       _currentRootForKeys = 0;
+
+    /**
+     * This method is used to pass the largest DOM size to the translet.
+     * Needed to make sure that the translet can index the whole DOM.
+     */
+    public void setIndexSize(int size) {
+        if (size > _indexSize) _indexSize = size;
+    }
+
+    /**
+     * Creates a KeyIndex object of the desired size - don't want to resize!!!
+     */
+    public KeyIndex createKeyIndex() {
+        return(new KeyIndex(_indexSize));
+    }
+
+    /**
+     * Adds a value to a key/id index
+     *   @param name is the name of the index (the key or ##id)
+     *   @param node is the node handle of the node to insert
+     *   @param value is the value that will look up the node in the given index
+     */
+    public void buildKeyIndex(String name, int node, Object value) {
+        if (_keyIndexes == null) _keyIndexes = new Hashtable();
+
+        KeyIndex index = (KeyIndex)_keyIndexes.get(name);
+        if (index == null) {
+            _keyIndexes.put(name, index = new KeyIndex(_indexSize));
+        }
+        index.add(value, node, _currentRootForKeys);
+    }
+
+    /**
+     * Create an empty KeyIndex in the DOM case
+     *   @param name is the name of the index (the key or ##id)
+     *   @param dom is the DOM
+     */
+    public void buildKeyIndex(String name, DOM dom) {
+        if (_keyIndexes == null) _keyIndexes = new Hashtable();
+
+        KeyIndex index = (KeyIndex)_keyIndexes.get(name);
+        if (index == null) {
+            _keyIndexes.put(name, index = new KeyIndex(_indexSize));
+        }
+        index.setDom(dom, dom.getDocument());
+    }
+
+    /**
+     * Returns the index for a given key (or id).
+     * The index implements our internal iterator interface
+     */
+    public KeyIndex getKeyIndex(String name) {
+        // Return an empty key index iterator if none are defined
+        if (_keyIndexes == null) {
+            return (_emptyKeyIndex != null)
+                ? _emptyKeyIndex
+                : (_emptyKeyIndex = new KeyIndex(1));
+        }
+
+        // Look up the requested key index
+        final KeyIndex index = (KeyIndex)_keyIndexes.get(name);
+
+        // Return an empty key index iterator if the requested index not found
+        if (index == null) {
+            return (_emptyKeyIndex != null)
+                ? _emptyKeyIndex
+                : (_emptyKeyIndex = new KeyIndex(1));
+        }
+
+        return(index);
+    }
+
+    private void setRootForKeys(int root) {
+        _currentRootForKeys = root;
+    }
+
+    /**
+     * This method builds key indexes - it is overridden in the compiled
+     * translet in cases where the <xsl:key> element is used
+     */
+    public void buildKeys(DOM document, DTMAxisIterator iterator,
+                          SerializationHandler handler,
+                          int root) throws TransletException {
+
+    }
+
+    /**
+     * This method builds key indexes - it is overridden in the compiled
+     * translet in cases where the <xsl:key> element is used
+     */
+    public void setKeyIndexDom(String name, DOM document) {
+        getKeyIndex(name).setDom(document, document.getDocument());
+    }
+
+    /************************************************************************
+     * DOM cache handling
+     ************************************************************************/
+
+    // Hold the DOM cache (if any) used with this translet
+    private DOMCache _domCache = null;
+
+    /**
+     * Sets the DOM cache used for additional documents loaded using the
+     * document() function.
+     */
+    public void setDOMCache(DOMCache cache) {
+        _domCache = cache;
+    }
+
+    /**
+     * Returns the DOM cache used for this translet. Used by the LoadDocument
+     * class (if present) when the document() function is used.
+     */
+    public DOMCache getDOMCache() {
+        return(_domCache);
+    }
+
+    /************************************************************************
+     * Multiple output document extension.
+     * See compiler/TransletOutput for actual implementation.
+     ************************************************************************/
+
+    public SerializationHandler openOutputHandler(String filename, boolean append)
+        throws TransletException
+    {
+        try {
+            final TransletOutputHandlerFactory factory
+                = TransletOutputHandlerFactory.newInstance();
+
+            String dirStr = new File(filename).getParent();
+            if ((null != dirStr) && (dirStr.length() > 0)) {
+               File dir = new File(dirStr);
+               dir.mkdirs();
+            }
+
+            factory.setEncoding(_encoding);
+            factory.setOutputMethod(_method);
+            factory.setOutputStream(new BufferedOutputStream(new FileOutputStream(filename, append)));
+            factory.setOutputType(TransletOutputHandlerFactory.STREAM);
+
+            final SerializationHandler handler
+                = factory.getSerializationHandler();
+
+            transferOutputSettings(handler);
+            handler.startDocument();
+            return handler;
+        }
+        catch (Exception e) {
+            throw new TransletException(e);
+        }
+    }
+
+    public SerializationHandler openOutputHandler(String filename)
+       throws TransletException
+    {
+       return openOutputHandler(filename, false);
+    }
+
+    public void closeOutputHandler(SerializationHandler handler) {
+        try {
+            handler.endDocument();
+            handler.close();
+        }
+        catch (Exception e) {
+            // what can you do?
+        }
+    }
+
+    /************************************************************************
+     * Native API transformation methods - _NOT_ JAXP/TrAX
+     ************************************************************************/
+
+    /**
+     * Main transform() method - this is overridden by the compiled translet
+     */
+    public abstract void transform(DOM document, DTMAxisIterator iterator,
+                                   SerializationHandler handler)
+        throws TransletException;
+
+    /**
+     * Calls transform() with a given output handler
+     */
+    public final void transform(DOM document, SerializationHandler handler)
+        throws TransletException {
+        try {
+            transform(document, document.getIterator(), handler);
+        } finally {
+            _keyIndexes = null;
+        }
+    }
+
+    /**
+     * Used by some compiled code as a shortcut for passing strings to the
+     * output handler
+     */
+    public final void characters(final String string,
+                                 SerializationHandler handler)
+        throws TransletException {
+        if (string != null) {
+           //final int length = string.length();
+           try {
+               handler.characters(string);
+           } catch (Exception e) {
+               throw new TransletException(e);
+           }
+        }
+    }
+
+    /**
+     * Add's a name of an element whose text contents should be output as CDATA
+     */
+    public void addCdataElement(String name) {
+        if (_cdata == null) {
+            _cdata = new Vector();
+        }
+
+        int lastColon = name.lastIndexOf(':');
+
+        if (lastColon > 0) {
+            String uri = name.substring(0, lastColon);
+            String localName = name.substring(lastColon+1);
+            _cdata.addElement(uri);
+            _cdata.addElement(localName);
+        } else {
+            _cdata.addElement(null);
+            _cdata.addElement(name);
+        }
+    }
+
+    /**
+     * Transfer the output settings to the output post-processor
+     */
+    protected void transferOutputSettings(SerializationHandler handler) {
+        if (_method != null) {
+            if (_method.equals("xml")) {
+                if (_standalone != null) {
+                    handler.setStandalone(_standalone);
+                }
+                if (_omitHeader) {
+                    handler.setOmitXMLDeclaration(true);
+                }
+                handler.setCdataSectionElements(_cdata);
+                if (_version != null) {
+                    handler.setVersion(_version);
+                }
+                handler.setIndent(_indent);
+                handler.setIndentAmount(_indentamount);
+                if (_doctypeSystem != null) {
+                    handler.setDoctype(_doctypeSystem, _doctypePublic);
+                }
+            }
+            else if (_method.equals("html")) {
+                handler.setIndent(_indent);
+                handler.setDoctype(_doctypeSystem, _doctypePublic);
+                if (_mediaType != null) {
+                    handler.setMediaType(_mediaType);
+                }
+            }
+        }
+        else {
+            handler.setCdataSectionElements(_cdata);
+            if (_version != null) {
+                handler.setVersion(_version);
+            }
+            if (_standalone != null) {
+                handler.setStandalone(_standalone);
+            }
+            if (_omitHeader) {
+                handler.setOmitXMLDeclaration(true);
+            }
+            handler.setIndent(_indent);
+            handler.setDoctype(_doctypeSystem, _doctypePublic);
+        }
+    }
+
+    private Hashtable _auxClasses = null;
+
+    public void addAuxiliaryClass(Class auxClass) {
+        if (_auxClasses == null) _auxClasses = new Hashtable();
+        _auxClasses.put(auxClass.getName(), auxClass);
+    }
+
+    public void setAuxiliaryClasses(Hashtable auxClasses) {
+        _auxClasses = auxClasses;
+    }
+
+    public Class getAuxiliaryClass(String className) {
+        if (_auxClasses == null) return null;
+        return((Class)_auxClasses.get(className));
+    }
+
+    // GTM added (see pg 110)
+    public String[] getNamesArray() {
+        return namesArray;
+    }
+
+    public String[] getUrisArray() {
+        return urisArray;
+    }
+
+    public int[] getTypesArray() {
+        return typesArray;
+    }
+
+    public String[] getNamespaceArray() {
+        return namespaceArray;
+    }
+
+    public boolean hasIdCall() {
+        return _hasIdCall;
+    }
+
+    public Templates getTemplates() {
+        return _templates;
+    }
+
+    public void setTemplates(Templates templates) {
+        _templates = templates;
+    }
+
+    /************************************************************************
+     * DOMImplementation caching for basis library
+     ************************************************************************/
+    protected DOMImplementation _domImplementation = null;
+
+    public Document newDocument(String uri, String qname)
+        throws ParserConfigurationException
+    {
+        if (_domImplementation == null) {
+            _domImplementation = DocumentBuilderFactory.newInstance()
+                .newDocumentBuilder().getDOMImplementation();
+        }
+        return _domImplementation.createDocument(uri, qname, null);
+    }
+}