jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java
changeset 25868 686eef1e7a79
parent 23092 64904fcdd0ee
child 28694 b99e1eee0669
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java	Sun Aug 17 15:51:56 2014 +0100
@@ -0,0 +1,1673 @@
+/*
+ * 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: BasisLibrary.java,v 1.6 2006/06/20 21:51:58 spericas Exp $
+ */
+
+package com.sun.org.apache.xalan.internal.xsltc.runtime;
+
+import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.xml.transform.dom.DOMSource;
+
+import com.sun.org.apache.xalan.internal.xsltc.DOM;
+import com.sun.org.apache.xalan.internal.xsltc.Translet;
+import com.sun.org.apache.xalan.internal.xsltc.dom.AbsoluteIterator;
+import com.sun.org.apache.xml.internal.dtm.Axis;
+import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
+import com.sun.org.apache.xalan.internal.xsltc.dom.MultiDOM;
+import com.sun.org.apache.xalan.internal.xsltc.dom.SingletonIterator;
+import com.sun.org.apache.xalan.internal.xsltc.dom.StepIterator;
+import com.sun.org.apache.xalan.internal.xsltc.dom.ArrayNodeListIterator;
+import com.sun.org.apache.xml.internal.dtm.DTM;
+import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
+import com.sun.org.apache.xml.internal.dtm.DTMManager;
+import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
+import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import com.sun.org.apache.xml.internal.serializer.NamespaceMappings;
+import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
+import com.sun.org.apache.xml.internal.utils.XML11Char;
+
+/**
+ * Standard XSLT functions. All standard functions expect the current node
+ * and the DOM as their last two arguments.
+ */
+public final class BasisLibrary {
+
+    private final static String EMPTYSTRING = "";
+
+    /**
+     * Re-use a single instance of StringBuffer (per thread) in the basis library.
+     * StringBuilder is better, however, DecimalFormat only accept StringBuffer
+     */
+    private static final ThreadLocal<StringBuilder> threadLocalStringBuilder =
+        new ThreadLocal<StringBuilder> () {
+            @Override protected StringBuilder initialValue() {
+                return new StringBuilder();
+            }
+    };
+
+    /**
+     * ThreadLocal for StringBuffer used
+     */
+    private static final ThreadLocal<StringBuffer> threadLocalStringBuffer =
+        new ThreadLocal<StringBuffer> () {
+            @Override protected StringBuffer initialValue() {
+                return new StringBuffer();
+            }
+    };
+
+    /**
+     * Standard function count(node-set)
+     */
+    public static int countF(DTMAxisIterator iterator) {
+        return(iterator.getLast());
+    }
+
+    /**
+     * Standard function position()
+     * @deprecated This method exists only for backwards compatibility with old
+     *             translets.  New code should not reference it.
+     */
+    public static int positionF(DTMAxisIterator iterator) {
+        return iterator.isReverse()
+                     ? iterator.getLast() - iterator.getPosition() + 1
+                     : iterator.getPosition();
+    }
+
+    /**
+     * XSLT Standard function sum(node-set).
+     * stringToDouble is inlined
+     */
+    public static double sumF(DTMAxisIterator iterator, DOM dom) {
+        try {
+            double result = 0.0;
+            int node;
+            while ((node = iterator.next()) != DTMAxisIterator.END) {
+                result += Double.parseDouble(dom.getStringValueX(node));
+            }
+            return result;
+        }
+        catch (NumberFormatException e) {
+            return Double.NaN;
+        }
+    }
+
+    /**
+     * XSLT Standard function string()
+     */
+    public static String stringF(int node, DOM dom) {
+        return dom.getStringValueX(node);
+    }
+
+    /**
+     * XSLT Standard function string(value)
+     */
+    public static String stringF(Object obj, DOM dom) {
+        if (obj instanceof DTMAxisIterator) {
+            return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
+        }
+        else if (obj instanceof Node) {
+            return dom.getStringValueX(((Node)obj).node);
+        }
+        else if (obj instanceof DOM) {
+            return ((DOM)obj).getStringValue();
+        }
+        else {
+            return obj.toString();
+        }
+    }
+
+    /**
+     * XSLT Standard function string(value)
+     */
+    public static String stringF(Object obj, int node, DOM dom) {
+        if (obj instanceof DTMAxisIterator) {
+            return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
+        }
+        else if (obj instanceof Node) {
+            return dom.getStringValueX(((Node)obj).node);
+        }
+        else if (obj instanceof DOM) {
+            // When the first argument is a DOM we want the whole
+            // DOM and not just a single node - that would not make sense.
+            //return ((DOM)obj).getStringValueX(node);
+            return ((DOM)obj).getStringValue();
+        }
+        else if (obj instanceof Double) {
+            Double d = (Double)obj;
+            final String result = d.toString();
+            final int length = result.length();
+            if ((result.charAt(length-2)=='.') &&
+                (result.charAt(length-1) == '0'))
+                return result.substring(0, length-2);
+            else
+                return result;
+        }
+        else {
+            return obj != null ? obj.toString() : "";
+        }
+    }
+
+    /**
+     * XSLT Standard function number()
+     */
+    public static double numberF(int node, DOM dom) {
+        return stringToReal(dom.getStringValueX(node));
+    }
+
+    /**
+     * XSLT Standard function number(value)
+     */
+    public static double numberF(Object obj, DOM dom) {
+        if (obj instanceof Double) {
+            return ((Double) obj).doubleValue();
+        }
+        else if (obj instanceof Integer) {
+            return ((Integer) obj).doubleValue();
+        }
+        else if (obj instanceof Boolean) {
+            return  ((Boolean) obj).booleanValue() ? 1.0 : 0.0;
+        }
+        else if (obj instanceof String) {
+            return stringToReal((String) obj);
+        }
+        else if (obj instanceof DTMAxisIterator) {
+            DTMAxisIterator iter = (DTMAxisIterator) obj;
+            return stringToReal(dom.getStringValueX(iter.reset().next()));
+        }
+        else if (obj instanceof Node) {
+            return stringToReal(dom.getStringValueX(((Node) obj).node));
+        }
+        else if (obj instanceof DOM) {
+            return stringToReal(((DOM) obj).getStringValue());
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(INVALID_ARGUMENT_ERR, className, "number()");
+            return 0.0;
+        }
+    }
+
+    /**
+     * XSLT Standard function round()
+     */
+    public static double roundF(double d) {
+            return (d<-0.5 || d>0.0)?Math.floor(d+0.5):((d==0.0)?
+                        d:(Double.isNaN(d)?Double.NaN:-0.0));
+    }
+
+    /**
+     * XSLT Standard function boolean()
+     */
+    public static boolean booleanF(Object obj) {
+        if (obj instanceof Double) {
+            final double temp = ((Double) obj).doubleValue();
+            return temp != 0.0 && !Double.isNaN(temp);
+        }
+        else if (obj instanceof Integer) {
+            return ((Integer) obj).doubleValue() != 0;
+        }
+        else if (obj instanceof Boolean) {
+            return  ((Boolean) obj).booleanValue();
+        }
+        else if (obj instanceof String) {
+            return !((String) obj).equals(EMPTYSTRING);
+        }
+        else if (obj instanceof DTMAxisIterator) {
+            DTMAxisIterator iter = (DTMAxisIterator) obj;
+            return iter.reset().next() != DTMAxisIterator.END;
+        }
+        else if (obj instanceof Node) {
+            return true;
+        }
+        else if (obj instanceof DOM) {
+            String temp = ((DOM) obj).getStringValue();
+            return !temp.equals(EMPTYSTRING);
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(INVALID_ARGUMENT_ERR, className, "boolean()");
+        }
+        return false;
+    }
+
+    /**
+     * XSLT Standard function substring(). Must take a double because of
+     * conversions resulting into NaNs and rounding.
+     */
+    public static String substringF(String value, double start) {
+        if (Double.isNaN(start))
+            return(EMPTYSTRING);
+
+            final int strlen = value.length();
+            int istart = (int)Math.round(start) - 1;
+
+        if (istart > strlen)
+            return(EMPTYSTRING);
+        if (istart < 1)
+            istart = 0;
+        try {
+            return value.substring(istart);
+        } catch (IndexOutOfBoundsException e) {
+            runTimeError(RUN_TIME_INTERNAL_ERR, "substring()");
+            return null;
+        }
+    }
+
+    /**
+     * XSLT Standard function substring(). Must take a double because of
+     * conversions resulting into NaNs and rounding.
+     */
+    public static String substringF(String value, double start, double length) {
+        if (Double.isInfinite(start) ||
+            Double.isNaN(start) ||
+            Double.isNaN(length))
+            return(EMPTYSTRING);
+
+            int istart = (int)Math.round(start) - 1;
+        final int isum;
+        if (Double.isInfinite(length))
+            isum = Integer.MAX_VALUE;
+        else
+            isum = istart + (int)Math.round(length);
+
+        final int strlen = value.length();
+        if (isum < 0 || istart > strlen)
+                return(EMPTYSTRING);
+
+        if (istart < 0)
+            istart = 0;
+
+        try {
+            if (isum > strlen)
+                return value.substring(istart);
+            else
+                return value.substring(istart, isum);
+        } catch (IndexOutOfBoundsException e) {
+            runTimeError(RUN_TIME_INTERNAL_ERR, "substring()");
+            return null;
+        }
+    }
+
+    /**
+     * XSLT Standard function substring-after().
+     */
+    public static String substring_afterF(String value, String substring) {
+        final int index = value.indexOf(substring);
+        if (index >= 0)
+            return value.substring(index + substring.length());
+        else
+            return EMPTYSTRING;
+    }
+
+    /**
+     * XSLT Standard function substring-before().
+     */
+    public static String substring_beforeF(String value, String substring) {
+        final int index = value.indexOf(substring);
+        if (index >= 0)
+            return value.substring(0, index);
+        else
+            return EMPTYSTRING;
+    }
+
+    /**
+     * XSLT Standard function translate().
+     */
+    public static String translateF(String value, String from, String to) {
+        final int tol = to.length();
+        final int froml = from.length();
+        final int valuel = value.length();
+
+        final StringBuilder result = threadLocalStringBuilder.get();
+    result.setLength(0);
+        for (int j, i = 0; i < valuel; i++) {
+            final char ch = value.charAt(i);
+            for (j = 0; j < froml; j++) {
+                if (ch == from.charAt(j)) {
+                    if (j < tol)
+                        result.append(to.charAt(j));
+                    break;
+                }
+            }
+            if (j == froml)
+                result.append(ch);
+        }
+        return result.toString();
+    }
+
+    /**
+     * XSLT Standard function normalize-space().
+     */
+    public static String normalize_spaceF(int node, DOM dom) {
+        return normalize_spaceF(dom.getStringValueX(node));
+    }
+
+    /**
+     * XSLT Standard function normalize-space(string).
+     */
+    public static String normalize_spaceF(String value) {
+        int i = 0, n = value.length();
+        StringBuilder result = threadLocalStringBuilder.get();
+    result.setLength(0);
+
+        while (i < n && isWhiteSpace(value.charAt(i)))
+            i++;
+
+        while (true) {
+            while (i < n && !isWhiteSpace(value.charAt(i))) {
+                result.append(value.charAt(i++));
+            }
+            if (i == n)
+                break;
+            while (i < n && isWhiteSpace(value.charAt(i))) {
+                i++;
+            }
+            if (i < n)
+                result.append(' ');
+        }
+        return result.toString();
+    }
+
+    /**
+     * XSLT Standard function generate-id().
+     */
+    public static String generate_idF(int node) {
+        if (node > 0)
+            // Only generate ID if node exists
+            return "N" + node;
+        else
+            // Otherwise return an empty string
+            return EMPTYSTRING;
+    }
+
+    /**
+     * utility function for calls to local-name().
+     */
+    public static String getLocalName(String value) {
+        int idx = value.lastIndexOf(':');
+        if (idx >= 0) value = value.substring(idx + 1);
+        idx = value.lastIndexOf('@');
+        if (idx >= 0) value = value.substring(idx + 1);
+        return(value);
+    }
+
+    /**
+     * External functions that cannot be resolved are replaced with a call
+     * to this method. This method will generate a runtime errors. A good
+     * stylesheet checks whether the function exists using conditional
+     * constructs, and never really tries to call it if it doesn't exist.
+     * But simple stylesheets may result in a call to this method.
+     * The compiler should generate a warning if it encounters a call to
+     * an unresolved external function.
+     */
+    public static void unresolved_externalF(String name) {
+        runTimeError(EXTERNAL_FUNC_ERR, name);
+    }
+
+    /**
+     * Utility function to throw a runtime error on the use of an extension
+     * function when the secure processing feature is set to true.
+     */
+    public static void unallowed_extension_functionF(String name) {
+        runTimeError(UNALLOWED_EXTENSION_FUNCTION_ERR, name);
+    }
+
+    /**
+     * Utility function to throw a runtime error on the use of an extension
+     * element when the secure processing feature is set to true.
+     */
+    public static void unallowed_extension_elementF(String name) {
+        runTimeError(UNALLOWED_EXTENSION_ELEMENT_ERR, name);
+    }
+
+    /**
+     * Utility function to throw a runtime error for an unsupported element.
+     *
+     * This is only used in forward-compatibility mode, when the control flow
+     * cannot be determined. In 1.0 mode, the error message is emitted at
+     * compile time.
+     */
+    public static void unsupported_ElementF(String qname, boolean isExtension) {
+        if (isExtension)
+            runTimeError(UNSUPPORTED_EXT_ERR, qname);
+        else
+            runTimeError(UNSUPPORTED_XSL_ERR, qname);
+    }
+
+    /**
+     * XSLT Standard function namespace-uri(node-set).
+     */
+    public static String namespace_uriF(DTMAxisIterator iter, DOM dom) {
+        return namespace_uriF(iter.next(), dom);
+    }
+
+    /**
+     * XSLT Standard function system-property(name)
+     */
+    public static String system_propertyF(String name) {
+        if (name.equals("xsl:version"))
+            return("1.0");
+        if (name.equals("xsl:vendor"))
+            return("Apache Software Foundation (Xalan XSLTC)");
+        if (name.equals("xsl:vendor-url"))
+            return("http://xml.apache.org/xalan-j");
+
+        runTimeError(INVALID_ARGUMENT_ERR, name, "system-property()");
+        return(EMPTYSTRING);
+    }
+
+    /**
+     * XSLT Standard function namespace-uri().
+     */
+    public static String namespace_uriF(int node, DOM dom) {
+        final String value = dom.getNodeName(node);
+        final int colon = value.lastIndexOf(':');
+        if (colon >= 0)
+            return value.substring(0, colon);
+        else
+            return EMPTYSTRING;
+    }
+
+    /**
+     * Implements the object-type() extension function.
+     *
+     * @see <a href="http://www.exslt.org/">EXSLT</a>
+     */
+    public static String objectTypeF(Object obj)
+    {
+      if (obj instanceof String)
+        return "string";
+      else if (obj instanceof Boolean)
+        return "boolean";
+      else if (obj instanceof Number)
+        return "number";
+      else if (obj instanceof DOM)
+        return "RTF";
+      else if (obj instanceof DTMAxisIterator)
+        return "node-set";
+      else
+        return "unknown";
+    }
+
+    /**
+     * Implements the nodeset() extension function.
+     */
+    public static DTMAxisIterator nodesetF(Object obj) {
+        if (obj instanceof DOM) {
+           //final DOMAdapter adapter = (DOMAdapter) obj;
+           final DOM dom = (DOM)obj;
+           return new SingletonIterator(dom.getDocument(), true);
+        }
+        else if (obj instanceof DTMAxisIterator) {
+           return (DTMAxisIterator) obj;
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, "node-set", className);
+            return null;
+        }
+    }
+
+    //-- Begin utility functions
+
+    private static boolean isWhiteSpace(char ch) {
+        return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+    }
+
+    private static boolean compareStrings(String lstring, String rstring,
+                                          int op, DOM dom) {
+        switch (op) {
+    case Operators.EQ:
+            return lstring.equals(rstring);
+
+    case Operators.NE:
+            return !lstring.equals(rstring);
+
+    case Operators.GT:
+            return numberF(lstring, dom) > numberF(rstring, dom);
+
+    case Operators.LT:
+            return numberF(lstring, dom) < numberF(rstring, dom);
+
+    case Operators.GE:
+            return numberF(lstring, dom) >= numberF(rstring, dom);
+
+    case Operators.LE:
+            return numberF(lstring, dom) <= numberF(rstring, dom);
+
+        default:
+            runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
+            return false;
+        }
+    }
+
+    /**
+     * Utility function: node-set/node-set compare.
+     */
+    public static boolean compare(DTMAxisIterator left, DTMAxisIterator right,
+                                  int op, DOM dom) {
+        int lnode;
+        left.reset();
+
+        while ((lnode = left.next()) != DTMAxisIterator.END) {
+            final String lvalue = dom.getStringValueX(lnode);
+
+            int rnode;
+            right.reset();
+            while ((rnode = right.next()) != DTMAxisIterator.END) {
+                // String value must be the same if both nodes are the same
+                if (lnode == rnode) {
+                    if (op == Operators.EQ) {
+                        return true;
+                    } else if (op == Operators.NE) {
+                        continue;
+                    }
+                }
+                if (compareStrings(lvalue, dom.getStringValueX(rnode), op,
+                                   dom)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean compare(int node, DTMAxisIterator iterator,
+                                  int op, DOM dom) {
+        //iterator.reset();
+
+        int rnode;
+        String value;
+
+        switch(op) {
+    case Operators.EQ:
+            rnode = iterator.next();
+            if (rnode != DTMAxisIterator.END) {
+                value = dom.getStringValueX(node);
+                do {
+                    if (node == rnode
+                          || value.equals(dom.getStringValueX(rnode))) {
+                       return true;
+                    }
+                } while ((rnode = iterator.next()) != DTMAxisIterator.END);
+            }
+            break;
+    case Operators.NE:
+            rnode = iterator.next();
+            if (rnode != DTMAxisIterator.END) {
+                value = dom.getStringValueX(node);
+                do {
+                    if (node != rnode
+                          && !value.equals(dom.getStringValueX(rnode))) {
+                        return true;
+                    }
+                } while ((rnode = iterator.next()) != DTMAxisIterator.END);
+            }
+            break;
+    case Operators.LT:
+            // Assume we're comparing document order here
+            while ((rnode = iterator.next()) != DTMAxisIterator.END) {
+                if (rnode > node) return true;
+            }
+            break;
+    case Operators.GT:
+            // Assume we're comparing document order here
+            while ((rnode = iterator.next()) != DTMAxisIterator.END) {
+                if (rnode < node) return true;
+            }
+            break;
+        }
+        return(false);
+    }
+
+    /**
+     * Utility function: node-set/number compare.
+     */
+    public static boolean compare(DTMAxisIterator left, final double rnumber,
+                                  final int op, DOM dom) {
+        int node;
+        //left.reset();
+
+        switch (op) {
+    case Operators.EQ:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) == rnumber)
+                    return true;
+            }
+            break;
+
+    case Operators.NE:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) != rnumber)
+                    return true;
+            }
+            break;
+
+    case Operators.GT:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) > rnumber)
+                    return true;
+            }
+            break;
+
+    case Operators.LT:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) < rnumber)
+                    return true;
+            }
+            break;
+
+    case Operators.GE:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) >= rnumber)
+                    return true;
+            }
+            break;
+
+    case Operators.LE:
+            while ((node = left.next()) != DTMAxisIterator.END) {
+                if (numberF(dom.getStringValueX(node), dom) <= rnumber)
+                    return true;
+            }
+            break;
+
+        default:
+            runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
+        }
+
+        return false;
+    }
+
+    /**
+     * Utility function: node-set/string comparison.
+     */
+    public static boolean compare(DTMAxisIterator left, final String rstring,
+                                  int op, DOM dom) {
+        int node;
+        //left.reset();
+        while ((node = left.next()) != DTMAxisIterator.END) {
+            if (compareStrings(dom.getStringValueX(node), rstring, op, dom)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public static boolean compare(Object left, Object right,
+                                  int op, DOM dom)
+    {
+        boolean result = false;
+        boolean hasSimpleArgs = hasSimpleType(left) && hasSimpleType(right);
+
+    if (op != Operators.EQ && op != Operators.NE) {
+            // If node-boolean comparison -> convert node to boolean
+            if (left instanceof Node || right instanceof Node) {
+                if (left instanceof Boolean) {
+                    right = new Boolean(booleanF(right));
+                    hasSimpleArgs = true;
+                }
+                if (right instanceof Boolean) {
+                    left = new Boolean(booleanF(left));
+                    hasSimpleArgs = true;
+                }
+            }
+
+            if (hasSimpleArgs) {
+                switch (op) {
+        case Operators.GT:
+                    return numberF(left, dom) > numberF(right, dom);
+
+        case Operators.LT:
+                    return numberF(left, dom) < numberF(right, dom);
+
+        case Operators.GE:
+                    return numberF(left, dom) >= numberF(right, dom);
+
+        case Operators.LE:
+                    return numberF(left, dom) <= numberF(right, dom);
+
+        default:
+                    runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
+                }
+            }
+            // falls through
+        }
+
+        if (hasSimpleArgs) {
+            if (left instanceof Boolean || right instanceof Boolean) {
+                result = booleanF(left) == booleanF(right);
+            }
+            else if (left instanceof Double || right instanceof Double ||
+                     left instanceof Integer || right instanceof Integer) {
+                result = numberF(left, dom) == numberF(right, dom);
+            }
+            else { // compare them as strings
+                result = stringF(left, dom).equals(stringF(right, dom));
+            }
+
+            if (op == Operators.NE) {
+                result = !result;
+            }
+        }
+        else {
+            if (left instanceof Node) {
+                left = new SingletonIterator(((Node)left).node);
+            }
+            if (right instanceof Node) {
+                right = new SingletonIterator(((Node)right).node);
+            }
+
+            if (hasSimpleType(left) ||
+                left instanceof DOM && right instanceof DTMAxisIterator) {
+                // swap operands and operator
+                final Object temp = right; right = left; left = temp;
+                op = Operators.swapOp(op);
+            }
+
+            if (left instanceof DOM) {
+                if (right instanceof Boolean) {
+                    result = ((Boolean)right).booleanValue();
+                    return result == (op == Operators.EQ);
+                }
+
+                final String sleft = ((DOM)left).getStringValue();
+
+                if (right instanceof Number) {
+                    result = ((Number)right).doubleValue() ==
+                        stringToReal(sleft);
+                }
+                else if (right instanceof String) {
+                    result = sleft.equals((String)right);
+                }
+                else if (right instanceof DOM) {
+                    result = sleft.equals(((DOM)right).getStringValue());
+                }
+
+                if (op == Operators.NE) {
+                    result = !result;
+                }
+                return result;
+            }
+
+            // Next, node-set/t for t in {real, string, node-set, result-tree}
+
+            DTMAxisIterator iter = ((DTMAxisIterator)left).reset();
+
+            if (right instanceof DTMAxisIterator) {
+                result = compare(iter, (DTMAxisIterator)right, op, dom);
+            }
+            else if (right instanceof String) {
+                result = compare(iter, (String)right, op, dom);
+            }
+            else if (right instanceof Number) {
+                final double temp = ((Number)right).doubleValue();
+                result = compare(iter, temp, op, dom);
+            }
+            else if (right instanceof Boolean) {
+                boolean temp = ((Boolean)right).booleanValue();
+                result = (iter.reset().next() != DTMAxisIterator.END) == temp;
+            }
+            else if (right instanceof DOM) {
+                result = compare(iter, ((DOM)right).getStringValue(),
+                                 op, dom);
+            }
+            else if (right == null) {
+                return(false);
+            }
+            else {
+                final String className = right.getClass().getName();
+                runTimeError(INVALID_ARGUMENT_ERR, className, "compare()");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Utility function: used to test context node's language
+     */
+    public static boolean testLanguage(String testLang, DOM dom, int node) {
+        // language for context node (if any)
+        String nodeLang = dom.getLanguage(node);
+        if (nodeLang == null)
+            return(false);
+        else
+            nodeLang = nodeLang.toLowerCase();
+
+        // compare context node's language agains test language
+        testLang = testLang.toLowerCase();
+        if (testLang.length() == 2) {
+            return(nodeLang.startsWith(testLang));
+        }
+        else {
+            return(nodeLang.equals(testLang));
+        }
+    }
+
+    private static boolean hasSimpleType(Object obj) {
+        return obj instanceof Boolean || obj instanceof Double ||
+            obj instanceof Integer || obj instanceof String ||
+            obj instanceof Node || obj instanceof DOM;
+    }
+
+    /**
+     * Utility function: used in StringType to convert a string to a real.
+     */
+    public static double stringToReal(String s) {
+        try {
+            return Double.valueOf(s).doubleValue();
+        }
+        catch (NumberFormatException e) {
+            return Double.NaN;
+        }
+    }
+
+    /**
+     * Utility function: used in StringType to convert a string to an int.
+     */
+    public static int stringToInt(String s) {
+        try {
+            return Integer.parseInt(s);
+        }
+        catch (NumberFormatException e) {
+            return(-1); // ???
+        }
+    }
+
+    private static final int DOUBLE_FRACTION_DIGITS = 340;
+    private static final double lowerBounds = 0.001;
+    private static final double upperBounds = 10000000;
+    private static DecimalFormat defaultFormatter, xpathFormatter;
+    private static String defaultPattern = "";
+
+    static {
+        NumberFormat f = NumberFormat.getInstance(Locale.getDefault());
+        defaultFormatter = (f instanceof DecimalFormat) ?
+            (DecimalFormat) f : new DecimalFormat();
+        // Set max fraction digits so that truncation does not occur. Setting
+        // the max to Integer.MAX_VALUE may cause problems with some JDK's.
+        defaultFormatter.setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
+        defaultFormatter.setMinimumFractionDigits(0);
+        defaultFormatter.setMinimumIntegerDigits(1);
+        defaultFormatter.setGroupingUsed(false);
+
+        // This formatter is used to convert numbers according to the XPath
+        // 1.0 syntax which ignores locales (http://www.w3.org/TR/xpath#NT-Number)
+        xpathFormatter = new DecimalFormat("",
+            new DecimalFormatSymbols(Locale.US));
+        xpathFormatter.setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
+        xpathFormatter.setMinimumFractionDigits(0);
+        xpathFormatter.setMinimumIntegerDigits(1);
+        xpathFormatter.setGroupingUsed(false);
+    }
+
+    /**
+     * Utility function: used in RealType to convert a real to a string.
+     * Removes the decimal if null. Uses a specialized formatter object
+     * for very large and very small numbers that ignores locales, thus
+     * using always using "." as a decimal separator.
+     */
+    public static String realToString(double d) {
+        final double m = Math.abs(d);
+        if ((m >= lowerBounds) && (m < upperBounds)) {
+            final String result = Double.toString(d);
+            final int length = result.length();
+            // Remove leading zeros.
+            if ((result.charAt(length-2) == '.') &&
+                (result.charAt(length-1) == '0'))
+                return result.substring(0, length-2);
+            else
+                return result;
+        }
+        else {
+            if (Double.isNaN(d) || Double.isInfinite(d))
+                return(Double.toString(d));
+
+            //Convert -0.0 to +0.0 other values remains the same
+            d = d + 0.0;
+
+            // Use the XPath formatter to ignore locales
+            StringBuffer result = threadLocalStringBuffer.get();
+            result.setLength(0);
+            xpathFormatter.format(d, result, _fieldPosition);
+            return result.toString();
+        }
+    }
+
+    /**
+     * Utility function: used in RealType to convert a real to an integer
+     */
+    public static int realToInt(double d) {
+        return (int)d;
+    }
+
+    /**
+     * Utility function: used to format/adjust  a double to a string. The
+     * DecimalFormat object comes from the 'formatSymbols' hashtable in
+     * AbstractTranslet.
+     */
+    private static FieldPosition _fieldPosition = new FieldPosition(0);
+
+    public static String formatNumber(double number, String pattern,
+                                      DecimalFormat formatter) {
+        // bugzilla fix 12813
+        if (formatter == null) {
+            formatter = defaultFormatter;
+        }
+        try {
+            StringBuffer result = threadLocalStringBuffer.get();
+        result.setLength(0);
+            if (pattern != defaultPattern) {
+                formatter.applyLocalizedPattern(pattern);
+            }
+        formatter.format(number, result, _fieldPosition);
+            return result.toString();
+        }
+        catch (IllegalArgumentException e) {
+            runTimeError(FORMAT_NUMBER_ERR, Double.toString(number), pattern);
+            return(EMPTYSTRING);
+        }
+    }
+
+    /**
+     * Utility function: used to convert references to node-sets. If the
+     * obj is an instanceof Node then create a singleton iterator.
+     */
+    public static DTMAxisIterator referenceToNodeSet(Object obj) {
+        // Convert var/param -> node
+        if (obj instanceof Node) {
+            return(new SingletonIterator(((Node)obj).node));
+        }
+        // Convert var/param -> node-set
+        else if (obj instanceof DTMAxisIterator) {
+            return(((DTMAxisIterator)obj).cloneIterator().reset());
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, "node-set");
+            return null;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to org.w3c.dom.NodeList.
+     */
+    public static NodeList referenceToNodeList(Object obj, DOM dom) {
+        if (obj instanceof Node || obj instanceof DTMAxisIterator) {
+            DTMAxisIterator iter = referenceToNodeSet(obj);
+            return dom.makeNodeList(iter);
+        }
+        else if (obj instanceof DOM) {
+          dom = (DOM)obj;
+          return dom.makeNodeList(DTMDefaultBase.ROOTNODE);
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className,
+                "org.w3c.dom.NodeList");
+            return null;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to org.w3c.dom.Node.
+     */
+    public static org.w3c.dom.Node referenceToNode(Object obj, DOM dom) {
+        if (obj instanceof Node || obj instanceof DTMAxisIterator) {
+            DTMAxisIterator iter = referenceToNodeSet(obj);
+            return dom.makeNode(iter);
+        }
+        else if (obj instanceof DOM) {
+          dom = (DOM)obj;
+          DTMAxisIterator iter = dom.getChildren(DTMDefaultBase.ROOTNODE);
+          return dom.makeNode(iter);
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, "org.w3c.dom.Node");
+            return null;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to long.
+     */
+    public static long referenceToLong(Object obj) {
+        if (obj instanceof Number) {
+            return ((Number) obj).longValue();    // handles Integer and Double
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, Long.TYPE);
+            return 0;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to double.
+     */
+    public static double referenceToDouble(Object obj) {
+        if (obj instanceof Number) {
+            return ((Number) obj).doubleValue();   // handles Integer and Double
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, Double.TYPE);
+            return 0;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to boolean.
+     */
+    public static boolean referenceToBoolean(Object obj) {
+        if (obj instanceof Boolean) {
+            return ((Boolean) obj).booleanValue();
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, Boolean.TYPE);
+            return false;
+        }
+    }
+
+    /**
+     * Utility function: used to convert reference to String.
+     */
+    public static String referenceToString(Object obj, DOM dom) {
+        if (obj instanceof String) {
+            return (String) obj;
+        }
+        else if (obj instanceof DTMAxisIterator) {
+            return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
+        }
+        else if (obj instanceof Node) {
+            return dom.getStringValueX(((Node)obj).node);
+        }
+        else if (obj instanceof DOM) {
+            return ((DOM) obj).getStringValue();
+        }
+        else {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, className, String.class);
+            return null;
+        }
+    }
+
+    /**
+     * Utility function used to convert a w3c Node into an internal DOM iterator.
+     */
+    public static DTMAxisIterator node2Iterator(org.w3c.dom.Node node,
+        Translet translet, DOM dom)
+    {
+        final org.w3c.dom.Node inNode = node;
+        // Create a dummy NodeList which only contains the given node to make
+        // use of the nodeList2Iterator() interface.
+        org.w3c.dom.NodeList nodelist = new org.w3c.dom.NodeList() {
+            public int getLength() {
+                return 1;
+            }
+
+            public org.w3c.dom.Node item(int index) {
+                if (index == 0)
+                    return inNode;
+                else
+                    return null;
+            }
+        };
+
+        return nodeList2Iterator(nodelist, translet, dom);
+    }
+
+    /**
+     * In a perfect world, this would be the implementation for
+     * nodeList2Iterator. In reality, though, this causes a
+     * ClassCastException in getDTMHandleFromNode because SAXImpl is
+     * not an instance of DOM2DTM. So we use the more lengthy
+     * implementation below until this issue has been addressed.
+     *
+     * @see org.apache.xml.dtm.ref.DTMManagerDefault#getDTMHandleFromNode
+     */
+    private static DTMAxisIterator nodeList2IteratorUsingHandleFromNode(
+                                        org.w3c.dom.NodeList nodeList,
+                                        Translet translet, DOM dom)
+    {
+        final int n = nodeList.getLength();
+        final int[] dtmHandles = new int[n];
+        DTMManager dtmManager = null;
+        if (dom instanceof MultiDOM)
+            dtmManager = ((MultiDOM) dom).getDTMManager();
+        for (int i = 0; i < n; ++i) {
+            org.w3c.dom.Node node = nodeList.item(i);
+            int handle;
+            if (dtmManager != null) {
+                handle = dtmManager.getDTMHandleFromNode(node);
+            }
+            else if (node instanceof DTMNodeProxy
+                     && ((DTMNodeProxy) node).getDTM() == dom) {
+                handle = ((DTMNodeProxy) node).getDTMNodeNumber();
+            }
+            else {
+                runTimeError(RUN_TIME_INTERNAL_ERR, "need MultiDOM");
+                return null;
+            }
+            dtmHandles[i] = handle;
+            System.out.println("Node " + i + " has handle 0x" +
+                               Integer.toString(handle, 16));
+        }
+        return new ArrayNodeListIterator(dtmHandles);
+    }
+
+    /**
+     * Utility function used to convert a w3c NodeList into a internal
+     * DOM iterator.
+     */
+    public static DTMAxisIterator nodeList2Iterator(
+                                        org.w3c.dom.NodeList nodeList,
+                                        Translet translet, DOM dom)
+    {
+        // First pass: build w3c DOM for all nodes not proxied from our DOM.
+        //
+        // Notice: this looses some (esp. parent) context for these nodes,
+        // so some way to wrap the original nodes inside a DTMAxisIterator
+        // might be preferable in the long run.
+        int n = 0; // allow for change in list length, just in case.
+        Document doc = null;
+        DTMManager dtmManager = null;
+        int[] proxyNodes = new int[nodeList.getLength()];
+        if (dom instanceof MultiDOM)
+            dtmManager = ((MultiDOM) dom).getDTMManager();
+        for (int i = 0; i < nodeList.getLength(); ++i) {
+            org.w3c.dom.Node node = nodeList.item(i);
+            if (node instanceof DTMNodeProxy) {
+                DTMNodeProxy proxy = (DTMNodeProxy)node;
+                DTM nodeDTM = proxy.getDTM();
+                int handle = proxy.getDTMNodeNumber();
+                boolean isOurDOM = (nodeDTM == dom);
+                if (!isOurDOM && dtmManager != null) {
+                    try {
+                        isOurDOM = (nodeDTM == dtmManager.getDTM(handle));
+                    }
+                    catch (ArrayIndexOutOfBoundsException e) {
+                        // invalid node handle, so definitely not our doc
+                    }
+                }
+                if (isOurDOM) {
+                    proxyNodes[i] = handle;
+                    ++n;
+                    continue;
+                }
+            }
+            proxyNodes[i] = DTM.NULL;
+            int nodeType = node.getNodeType();
+            if (doc == null) {
+                if (dom instanceof MultiDOM == false) {
+                    runTimeError(RUN_TIME_INTERNAL_ERR, "need MultiDOM");
+                    return null;
+                }
+                try {
+                    AbstractTranslet at = (AbstractTranslet) translet;
+                    doc = at.newDocument("", "__top__");
+                }
+                catch (javax.xml.parsers.ParserConfigurationException e) {
+                    runTimeError(RUN_TIME_INTERNAL_ERR, e.getMessage());
+                    return null;
+                }
+            }
+            // Use one dummy element as container for each node of the
+            // list. That way, it is easier to detect resp. avoid
+            // funny things which change the number of nodes,
+            // e.g. auto-concatenation of text nodes.
+            Element mid;
+            switch (nodeType) {
+                case org.w3c.dom.Node.ELEMENT_NODE:
+                case org.w3c.dom.Node.TEXT_NODE:
+                case org.w3c.dom.Node.CDATA_SECTION_NODE:
+                case org.w3c.dom.Node.COMMENT_NODE:
+                case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
+                case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
+                    mid = doc.createElementNS(null, "__dummy__");
+                    mid.appendChild(doc.importNode(node, true));
+                    doc.getDocumentElement().appendChild(mid);
+                    ++n;
+                    break;
+                case org.w3c.dom.Node.ATTRIBUTE_NODE:
+                    // The mid element also serves as a container for
+                    // attributes, avoiding problems with conflicting
+                    // attributes or node order.
+                    mid = doc.createElementNS(null, "__dummy__");
+                    mid.setAttributeNodeNS((Attr)doc.importNode(node, true));
+                    doc.getDocumentElement().appendChild(mid);
+                    ++n;
+                    break;
+                default:
+                    // Better play it safe for all types we aren't sure we know
+                    // how to deal with.
+                    runTimeError(RUN_TIME_INTERNAL_ERR,
+                                 "Don't know how to convert node type "
+                                 + nodeType);
+            }
+        }
+
+        // w3cDOM -> DTM -> DOMImpl
+        DTMAxisIterator iter = null, childIter = null, attrIter = null;
+        if (doc != null) {
+            final MultiDOM multiDOM = (MultiDOM) dom;
+            DOM idom = (DOM)dtmManager.getDTM(new DOMSource(doc), false,
+                                              null, true, false);
+            // Create DOMAdapter and register with MultiDOM
+            DOMAdapter domAdapter = new DOMAdapter(idom,
+                translet.getNamesArray(),
+                translet.getUrisArray(),
+                translet.getTypesArray(),
+                translet.getNamespaceArray());
+            multiDOM.addDOMAdapter(domAdapter);
+
+            DTMAxisIterator iter1 = idom.getAxisIterator(Axis.CHILD);
+            DTMAxisIterator iter2 = idom.getAxisIterator(Axis.CHILD);
+            iter = new AbsoluteIterator(
+                new StepIterator(iter1, iter2));
+
+            iter.setStartNode(DTMDefaultBase.ROOTNODE);
+
+            childIter = idom.getAxisIterator(Axis.CHILD);
+            attrIter = idom.getAxisIterator(Axis.ATTRIBUTE);
+        }
+
+        // Second pass: find DTM handles for every node in the list.
+        int[] dtmHandles = new int[n];
+        n = 0;
+        for (int i = 0; i < nodeList.getLength(); ++i) {
+            if (proxyNodes[i] != DTM.NULL) {
+                dtmHandles[n++] = proxyNodes[i];
+                continue;
+            }
+            org.w3c.dom.Node node = nodeList.item(i);
+            DTMAxisIterator iter3 = null;
+            int nodeType = node.getNodeType();
+            switch (nodeType) {
+                case org.w3c.dom.Node.ELEMENT_NODE:
+                case org.w3c.dom.Node.TEXT_NODE:
+                case org.w3c.dom.Node.CDATA_SECTION_NODE:
+                case org.w3c.dom.Node.COMMENT_NODE:
+                case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
+                case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
+                    iter3 = childIter;
+                    break;
+                case org.w3c.dom.Node.ATTRIBUTE_NODE:
+                    iter3 = attrIter;
+                    break;
+                default:
+                    // Should not happen, as first run should have got all these
+                    throw new InternalRuntimeError("Mismatched cases");
+            }
+            if (iter3 != null) {
+                iter3.setStartNode(iter.next());
+                dtmHandles[n] = iter3.next();
+                // For now, play it self and perform extra checks:
+                if (dtmHandles[n] == DTMAxisIterator.END)
+                    throw new InternalRuntimeError("Expected element missing at " + i);
+                if (iter3.next() != DTMAxisIterator.END)
+                    throw new InternalRuntimeError("Too many elements at " + i);
+                ++n;
+            }
+        }
+        if (n != dtmHandles.length)
+            throw new InternalRuntimeError("Nodes lost in second pass");
+
+        return new ArrayNodeListIterator(dtmHandles);
+    }
+
+    /**
+     * Utility function used to convert references to DOMs.
+     */
+    public static DOM referenceToResultTree(Object obj) {
+        try {
+            return ((DOM) obj);
+        }
+        catch (IllegalArgumentException e) {
+            final String className = obj.getClass().getName();
+            runTimeError(DATA_CONVERSION_ERR, "reference", className);
+            return null;
+        }
+    }
+
+    /**
+     * Utility function: used with nth position filters to convert a sequence
+     * of nodes to just one single node (the one at position n).
+     */
+    public static DTMAxisIterator getSingleNode(DTMAxisIterator iterator) {
+        int node = iterator.next();
+        return(new SingletonIterator(node));
+    }
+
+    /**
+     * Utility function: used in xsl:copy.
+     */
+    private static char[] _characterArray = new char[32];
+
+    public static void copy(Object obj,
+                            SerializationHandler handler,
+                            int node,
+                            DOM dom) {
+        try {
+            if (obj instanceof DTMAxisIterator)
+      {
+                DTMAxisIterator iter = (DTMAxisIterator) obj;
+                dom.copy(iter.reset(), handler);
+            }
+            else if (obj instanceof Node) {
+                dom.copy(((Node) obj).node, handler);
+            }
+            else if (obj instanceof DOM) {
+                //((DOM)obj).copy(((com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase)((DOMAdapter)obj).getDOMImpl()).getDocument(), handler);
+                DOM newDom = (DOM)obj;
+                newDom.copy(newDom.getDocument(), handler);
+            }
+            else {
+                String string = obj.toString();         // or call stringF()
+                final int length = string.length();
+                if (length > _characterArray.length)
+                    _characterArray = new char[length];
+                string.getChars(0, length, _characterArray, 0);
+                handler.characters(_characterArray, 0, length);
+            }
+        }
+        catch (SAXException e) {
+            runTimeError(RUN_TIME_COPY_ERR);
+        }
+    }
+
+    /**
+     * Utility function to check if xsl:attribute has a valid qname
+     * This method should only be invoked if the name attribute is an AVT
+     */
+    public static void checkAttribQName(String name) {
+        final int firstOccur = name.indexOf(":");
+        final int lastOccur = name.lastIndexOf(":");
+        final String localName = name.substring(lastOccur + 1);
+
+        if (firstOccur > 0) {
+            final String newPrefix = name.substring(0, firstOccur);
+
+            if (firstOccur != lastOccur) {
+               final String oriPrefix = name.substring(firstOccur+1, lastOccur);
+                if (!XML11Char.isXML11ValidNCName(oriPrefix)) {
+                    // even though the orignal prefix is ignored, it should still get checked for valid NCName
+                    runTimeError(INVALID_QNAME_ERR,oriPrefix+":"+localName);
+                }
+            }
+
+            // prefix must be a valid NCName
+            if (!XML11Char.isXML11ValidNCName(newPrefix)) {
+                runTimeError(INVALID_QNAME_ERR,newPrefix+":"+localName);
+            }
+        }
+
+        // local name must be a valid NCName and must not be XMLNS
+        if ((!XML11Char.isXML11ValidNCName(localName))||(localName.equals(Constants.XMLNS_PREFIX))) {
+            runTimeError(INVALID_QNAME_ERR,localName);
+        }
+    }
+
+    /**
+     * Utility function to check if a name is a valid ncname
+     * This method should only be invoked if the attribute value is an AVT
+     */
+    public static void checkNCName(String name) {
+        if (!XML11Char.isXML11ValidNCName(name)) {
+            runTimeError(INVALID_NCNAME_ERR,name);
+        }
+    }
+
+    /**
+     * Utility function to check if a name is a valid qname
+     * This method should only be invoked if the attribute value is an AVT
+     */
+    public static void checkQName(String name) {
+        if (!XML11Char.isXML11ValidQName(name)) {
+            runTimeError(INVALID_QNAME_ERR,name);
+        }
+    }
+
+    /**
+     * Utility function for the implementation of xsl:element.
+     */
+    public static String startXslElement(String qname, String namespace,
+        SerializationHandler handler, DOM dom, int node)
+    {
+        try {
+            // Get prefix from qname
+            String prefix;
+            final int index = qname.indexOf(':');
+
+            if (index > 0) {
+                prefix = qname.substring(0, index);
+
+                // Handle case when prefix is not known at compile time
+                if (namespace == null || namespace.length() == 0) {
+                    try {
+                        // not sure if this line of code ever works
+                        namespace = dom.lookupNamespace(node, prefix);
+                    }
+                    catch(RuntimeException e) {
+                        handler.flushPending();  // need to flush or else can't get namespacemappings
+                        NamespaceMappings nm = handler.getNamespaceMappings();
+                        namespace = nm.lookupNamespace(prefix);
+                        if (namespace == null) {
+                            runTimeError(NAMESPACE_PREFIX_ERR,prefix);
+                        }
+                    }
+                }
+
+                handler.startElement(namespace, qname.substring(index+1),
+                                         qname);
+                handler.namespaceAfterStartElement(prefix, namespace);
+            }
+            else {
+                // Need to generate a prefix?
+                if (namespace != null && namespace.length() > 0) {
+                    prefix = generatePrefix();
+                    qname = prefix + ':' + qname;
+                    handler.startElement(namespace, qname, qname);
+                    handler.namespaceAfterStartElement(prefix, namespace);
+                }
+                else {
+                    handler.startElement(null, null, qname);
+                }
+            }
+        }
+        catch (SAXException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+
+        return qname;
+    }
+
+    /**
+     * This function is used in the execution of xsl:element
+     */
+    public static String getPrefix(String qname) {
+        final int index = qname.indexOf(':');
+        return (index > 0) ? qname.substring(0, index) : null;
+    }
+
+    /**
+     * This function is used in the execution of xsl:element
+     */
+    private static int prefixIndex = 0;
+
+    public static String generatePrefix() {
+        synchronized (BasisLibrary.class) {
+            return ("ns" + prefixIndex++);
+        }
+    }
+
+    public static final String RUN_TIME_INTERNAL_ERR =
+                                           "RUN_TIME_INTERNAL_ERR";
+    public static final String RUN_TIME_COPY_ERR =
+                                           "RUN_TIME_COPY_ERR";
+    public static final String DATA_CONVERSION_ERR =
+                                           "DATA_CONVERSION_ERR";
+    public static final String EXTERNAL_FUNC_ERR =
+                                           "EXTERNAL_FUNC_ERR";
+    public static final String EQUALITY_EXPR_ERR =
+                                           "EQUALITY_EXPR_ERR";
+    public static final String INVALID_ARGUMENT_ERR =
+                                           "INVALID_ARGUMENT_ERR";
+    public static final String FORMAT_NUMBER_ERR =
+                                           "FORMAT_NUMBER_ERR";
+    public static final String ITERATOR_CLONE_ERR =
+                                           "ITERATOR_CLONE_ERR";
+    public static final String AXIS_SUPPORT_ERR =
+                                           "AXIS_SUPPORT_ERR";
+    public static final String TYPED_AXIS_SUPPORT_ERR =
+                                           "TYPED_AXIS_SUPPORT_ERR";
+    public static final String STRAY_ATTRIBUTE_ERR =
+                                           "STRAY_ATTRIBUTE_ERR";
+    public static final String STRAY_NAMESPACE_ERR =
+                                           "STRAY_NAMESPACE_ERR";
+    public static final String NAMESPACE_PREFIX_ERR =
+                                           "NAMESPACE_PREFIX_ERR";
+    public static final String DOM_ADAPTER_INIT_ERR =
+                                           "DOM_ADAPTER_INIT_ERR";
+    public static final String PARSER_DTD_SUPPORT_ERR =
+                                           "PARSER_DTD_SUPPORT_ERR";
+    public static final String NAMESPACES_SUPPORT_ERR =
+                                           "NAMESPACES_SUPPORT_ERR";
+    public static final String CANT_RESOLVE_RELATIVE_URI_ERR =
+                                           "CANT_RESOLVE_RELATIVE_URI_ERR";
+    public static final String UNSUPPORTED_XSL_ERR =
+                                           "UNSUPPORTED_XSL_ERR";
+    public static final String UNSUPPORTED_EXT_ERR =
+                                           "UNSUPPORTED_EXT_ERR";
+    public static final String UNKNOWN_TRANSLET_VERSION_ERR =
+                                           "UNKNOWN_TRANSLET_VERSION_ERR";
+    public static final String INVALID_QNAME_ERR = "INVALID_QNAME_ERR";
+    public static final String INVALID_NCNAME_ERR = "INVALID_NCNAME_ERR";
+    public static final String UNALLOWED_EXTENSION_FUNCTION_ERR = "UNALLOWED_EXTENSION_FUNCTION_ERR";
+    public static final String UNALLOWED_EXTENSION_ELEMENT_ERR = "UNALLOWED_EXTENSION_ELEMENT_ERR";
+
+    // All error messages are localized and are stored in resource bundles.
+    private static ResourceBundle m_bundle;
+
+    public final static String ERROR_MESSAGES_KEY = "error-messages";
+
+    static {
+        String resource = "com.sun.org.apache.xalan.internal.xsltc.runtime.ErrorMessages";
+        m_bundle = SecuritySupport.getResourceBundle(resource);
+    }
+
+    /**
+     * Print a run-time error message.
+     */
+    public static void runTimeError(String code) {
+        throw new RuntimeException(m_bundle.getString(code));
+    }
+
+    public static void runTimeError(String code, Object[] args) {
+        final String message = MessageFormat.format(m_bundle.getString(code),
+                                                    args);
+        throw new RuntimeException(message);
+    }
+
+    public static void runTimeError(String code, Object arg0) {
+        runTimeError(code, new Object[]{ arg0 } );
+    }
+
+    public static void runTimeError(String code, Object arg0, Object arg1) {
+        runTimeError(code, new Object[]{ arg0, arg1 } );
+    }
+
+    public static void consoleOutput(String msg) {
+        System.out.println(msg);
+    }
+
+    /**
+     * Replace a certain character in a string with a new substring.
+     */
+    public static String replace(String base, char ch, String str) {
+        return (base.indexOf(ch) < 0) ? base :
+            replace(base, String.valueOf(ch), new String[] { str });
+    }
+
+    public static String replace(String base, String delim, String[] str) {
+        final int len = base.length();
+        final StringBuilder result = threadLocalStringBuilder.get();
+        result.setLength(0);
+
+        for (int i = 0; i < len; i++) {
+            final char ch = base.charAt(i);
+            final int k = delim.indexOf(ch);
+
+            if (k >= 0) {
+                result.append(str[k]);
+            }
+            else {
+                result.append(ch);
+            }
+        }
+        return result.toString();
+    }
+
+
+    /**
+     * Utility method to allow setting parameters of the form
+     * {namespaceuri}localName
+     * which get mapped to an instance variable in the class
+     * Hence  a parameter of the form "{http://foo.bar}xyz"
+     * will be replaced with the corresponding values
+     * by the BasisLibrary's utility method mapQNametoJavaName
+     * and thus get mapped to legal java variable names
+     */
+    public static String mapQNameToJavaName (String base ) {
+       return replace(base, ".-:/{}?#%*",
+                      new String[] { "$dot$", "$dash$" ,"$colon$", "$slash$",
+                                     "","$colon$","$ques$","$hash$","$per$",
+                                     "$aster$"});
+
+    }
+
+    /**
+     *  Utility method to calculate string-length as a number of code points,
+     *  to avoid possible errors with string that contains
+     *  complementary characters
+     */
+    public static int getStringLength(String str) {
+        return str.codePointCount(0,str.length());
+    }
+
+    //-- End utility functions
+}