| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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$ |
| */ |
| |
| package org.apache.xalan.xsltc.runtime; |
| |
| import java.text.DecimalFormat; |
| 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 org.apache.xalan.xsltc.DOM; |
| import org.apache.xalan.xsltc.Translet; |
| import org.apache.xalan.xsltc.dom.AbsoluteIterator; |
| import org.apache.xml.dtm.Axis; |
| import org.apache.xalan.xsltc.dom.DOMAdapter; |
| import org.apache.xalan.xsltc.dom.MultiDOM; |
| import org.apache.xalan.xsltc.dom.SingletonIterator; |
| import org.apache.xalan.xsltc.dom.StepIterator; |
| import org.apache.xml.dtm.DTMAxisIterator; |
| import org.apache.xml.dtm.DTMManager; |
| import org.apache.xml.dtm.ref.DTMDefaultBase; |
| |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| import org.apache.xml.serializer.NamespaceMappings; |
| import org.apache.xml.serializer.SerializationHandler; |
| import org.apache.xml.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 = ""; |
| |
| /** |
| * 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 { |
| if (obj != null) |
| return obj.toString(); |
| else |
| return stringF(node, dom); |
| } |
| } |
| |
| /** |
| * 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) { |
| try { |
| final int strlen = value.length(); |
| int istart = (int)Math.round(start) - 1; |
| |
| if (Double.isNaN(start)) return(EMPTYSTRING); |
| if (istart > strlen) return(EMPTYSTRING); |
| if (istart < 1) istart = 0; |
| |
| 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) { |
| try { |
| final int strlen = value.length(); |
| int istart = (int)Math.round(start) - 1; |
| int isum = istart + (int)Math.round(length); |
| |
| if (Double.isInfinite(length)) isum = Integer.MAX_VALUE; |
| |
| if (Double.isNaN(start) || Double.isNaN(length)) |
| return(EMPTYSTRING); |
| if (Double.isInfinite(start)) return(EMPTYSTRING); |
| if (istart > strlen) return(EMPTYSTRING); |
| if (isum < 0) return(EMPTYSTRING); |
| if (istart < 0) istart = 0; |
| |
| 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 StringBuffer result = new StringBuffer(); |
| 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(); |
| StringBuffer result = new StringBuffer(); |
| |
| 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; |
| 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); |
| } |
| |
| /** |
| * Utility function: used in RealType to convert a real to a string. |
| * Removes the decimal if null. |
| */ |
| 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)); |
| return formatNumber(d, defaultPattern, defaultFormatter); |
| } |
| } |
| |
| /** |
| * 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 = new StringBuffer(); |
| 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()); |
| } |
| 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); |
| } |
| |
| /** |
| * Utility function used to copy a node list to be under a parent node. |
| */ |
| private static void copyNodes(org.w3c.dom.NodeList nodeList, |
| org.w3c.dom.Document doc, org.w3c.dom.Node parent) |
| { |
| final int size = nodeList.getLength(); |
| |
| // copy Nodes from NodeList into new w3c DOM |
| for (int i = 0; i < size; i++) |
| { |
| org.w3c.dom.Node curr = nodeList.item(i); |
| int nodeType = curr.getNodeType(); |
| String value = null; |
| try { |
| value = curr.getNodeValue(); |
| } catch (DOMException ex) { |
| runTimeError(RUN_TIME_INTERNAL_ERR, ex.getMessage()); |
| return; |
| } |
| |
| String nodeName = curr.getNodeName(); |
| org.w3c.dom.Node newNode = null; |
| switch (nodeType){ |
| case org.w3c.dom.Node.ATTRIBUTE_NODE: |
| newNode = doc.createAttributeNS(curr.getNamespaceURI(), |
| nodeName); |
| break; |
| case org.w3c.dom.Node.CDATA_SECTION_NODE: |
| newNode = doc.createCDATASection(value); |
| break; |
| case org.w3c.dom.Node.COMMENT_NODE: |
| newNode = doc.createComment(value); |
| break; |
| case org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE: |
| newNode = doc.createDocumentFragment(); |
| break; |
| case org.w3c.dom.Node.DOCUMENT_NODE: |
| newNode = doc.createElementNS(null, "__document__"); |
| copyNodes(curr.getChildNodes(), doc, newNode); |
| break; |
| case org.w3c.dom.Node.DOCUMENT_TYPE_NODE: |
| // nothing? |
| break; |
| case org.w3c.dom.Node.ELEMENT_NODE: |
| // For Element node, also copy the children and the |
| // attributes. |
| org.w3c.dom.Element element = doc.createElementNS( |
| curr.getNamespaceURI(), nodeName); |
| if (curr.hasAttributes()) |
| { |
| org.w3c.dom.NamedNodeMap attributes = curr.getAttributes(); |
| for (int k = 0; k < attributes.getLength(); k++) { |
| org.w3c.dom.Node attr = attributes.item(k); |
| element.setAttributeNS(attr.getNamespaceURI(), |
| attr.getNodeName(), attr.getNodeValue()); |
| } |
| } |
| copyNodes(curr.getChildNodes(), doc, element); |
| newNode = element; |
| break; |
| case org.w3c.dom.Node.ENTITY_NODE: |
| // nothing ? |
| break; |
| case org.w3c.dom.Node.ENTITY_REFERENCE_NODE: |
| newNode = doc.createEntityReference(nodeName); |
| break; |
| case org.w3c.dom.Node.NOTATION_NODE: |
| // nothing ? |
| break; |
| case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE: |
| newNode = doc.createProcessingInstruction(nodeName, |
| value); |
| break; |
| case org.w3c.dom.Node.TEXT_NODE: |
| newNode = doc.createTextNode(value); |
| break; |
| } |
| try { |
| parent.appendChild(newNode); |
| } catch (DOMException e) { |
| runTimeError(RUN_TIME_INTERNAL_ERR, e.getMessage()); |
| return; |
| } |
| } |
| } |
| |
| /** |
| * 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) |
| { |
| // w3c NodeList -> w3c DOM |
| Document doc = null; |
| try { |
| doc = ((AbstractTranslet) translet).newDocument("", "__top__"); |
| } |
| catch (javax.xml.parsers.ParserConfigurationException e) { |
| runTimeError(RUN_TIME_INTERNAL_ERR, e.getMessage()); |
| return null; |
| } |
| |
| // Copy all the nodes in the nodelist to be under the top element |
| copyNodes(nodeList, doc, doc.getDocumentElement()); |
| |
| // w3cDOM -> DTM -> DOMImpl |
| if (dom instanceof MultiDOM) { |
| final MultiDOM multiDOM = (MultiDOM) dom; |
| |
| DTMDefaultBase dtm = (DTMDefaultBase)((DOMAdapter)multiDOM.getMain()).getDOMImpl(); |
| DTMManager dtmManager = dtm.getManager(); |
| |
| 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); |
| DTMAxisIterator iter = new AbsoluteIterator( |
| new StepIterator(iter1, iter2)); |
| |
| iter.setStartNode(DTMDefaultBase.ROOTNODE); |
| return iter; |
| } |
| else { |
| runTimeError(RUN_TIME_INTERNAL_ERR, "nodeList2Iterator()"); |
| return null; |
| } |
| } |
| |
| /** |
| * 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(((org.apache.xml.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) { |
| 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; |
| } |
| |
| /** |
| * <p>Look up the namespace for a lexical QName using the namespace |
| * declarations available at a particular location in the stylesheet.</p> |
| * <p>See {@link org.apache.xalan.xsltc.compiler.Stylesheet#compileStaticInitializer(org.apache.xalan.xsltc.compiler.util.ClassGenerator)} |
| * for more information about the <code>ancestorNodeIDs</code>, |
| * <code>prefixURIsIndex</code> and <code>prefixURIPairs</code arrays.</p> |
| * |
| * @param lexicalQName The QName as a <code>java.lang.String</code> |
| * @param stylesheetNodeID An <code>int</code> representing the element in |
| * the stylesheet relative to which the namespace of |
| * the lexical QName is to be determined |
| * @param ancestorNodeIDs An <code>int</code> array, indexed by stylesheet |
| * node IDs, containing the ID of the nearest ancestor |
| * node in the stylesheet that has namespace |
| * declarations, or <code>-1</code> if there is no |
| * such ancestor |
| * @param prefixURIsIndex An <code>int</code> array, indexed by stylesheet |
| * node IDs, containing the index into the |
| * <code>prefixURIPairs</code> array of the first |
| * prefix declared on that stylesheet node |
| * @param prefixURIPairs A <code>java.lang.String</code> array that contains |
| * pairs of |
| * @param ignoreDefault A <code>boolean</code> indicating whether any |
| * default namespace decarlation should be considered |
| * @return The namespace of the lexical QName or a zero-length string if |
| * the QName is in no namespace or no namespace declaration for the |
| * prefix of the QName was found |
| */ |
| public static String lookupStylesheetQNameNamespace(String lexicalQName, |
| int stylesheetNodeID, |
| int[] ancestorNodeIDs, |
| int[] prefixURIsIndex, |
| String[] prefixURIPairs, |
| boolean ignoreDefault) { |
| String prefix = getPrefix(lexicalQName); |
| String uri = ""; |
| |
| if (prefix == null && !ignoreDefault) { |
| prefix = ""; |
| } |
| |
| if (prefix != null) { |
| // Loop from current node in the stylesheet to its ancestors |
| nodeLoop: |
| for (int currentNodeID = stylesheetNodeID; |
| currentNodeID >= 0; |
| currentNodeID = ancestorNodeIDs[currentNodeID]) { |
| // Look at all declarations on the current stylesheet node |
| // The prefixURIsIndex is an array of indices into the |
| // prefixURIPairs array that are stored in ascending order. |
| // The declarations for a node I are in elements |
| // prefixURIsIndex[I] to prefixURIsIndex[I+1]-1 (or |
| // prefixURIPairs.length-1 if I is the last node) |
| int prefixStartIdx = prefixURIsIndex[currentNodeID]; |
| int prefixLimitIdx = (currentNodeID+1 < prefixURIsIndex.length) |
| ? prefixURIsIndex[currentNodeID + 1] |
| : prefixURIPairs.length; |
| |
| for (int prefixIdx = prefixStartIdx; |
| prefixIdx < prefixLimitIdx; |
| prefixIdx = prefixIdx + 2) { |
| // Did we find the declaration of our prefix |
| if (prefix.equals(prefixURIPairs[prefixIdx])) { |
| uri = prefixURIPairs[prefixIdx+1]; |
| break nodeLoop; |
| } |
| } |
| } |
| } |
| |
| return uri; |
| } |
| |
| /** |
| * <p>Look up the namespace for a lexical QName using the namespace |
| * declarations available at a particular location in the stylesheet and |
| * return the expanded QName</p> |
| * <p>See {@link org.apache.xalan.xsltc.compiler.Stylesheet#compileStaticInitializer(org.apache.xalan.xsltc.compiler.util.ClassGenerator)} |
| * for more information about the <code>ancestorNodeIDs</code>, |
| * <code>prefixURIsIndex</code> and <code>prefixURIPairs</code arrays.</p> |
| * |
| * @param lexicalQName The QName as a <code>java.lang.String</code> |
| * @param stylesheetNodeID An <code>int</code> representing the element in |
| * the stylesheet relative to which the namespace of |
| * the lexical QName is to be determined |
| * @param ancestorNodeIDs An <code>int</code> array, indexed by stylesheet |
| * node IDs, containing the ID of the nearest ancestor |
| * node in the stylesheet that has namespace |
| * declarations, or <code>-1</code> if there is no |
| * such ancestor |
| * @param prefixURIsIndex An <code>int</code> array, indexed by stylesheet |
| * node IDs, containing the index into the |
| * <code>prefixURIPairs</code> array of the first |
| * prefix declared on that stylesheet node |
| * @param prefixURIPairs A <code>java.lang.String</code> array that contains |
| * pairs of |
| * @param ignoreDefault A <code>boolean</code> indicating whether any |
| * default namespace decarlation should be considered |
| * @return The expanded QName in the form "uri:localName" or just |
| * "localName" if the QName is in no namespace or no namespace |
| * declaration for the prefix of the QName was found |
| */ |
| public static String expandStylesheetQNameRef(String lexicalQName, |
| int stylesheetNodeID, |
| int[] ancestorNodeIDs, |
| int[] prefixURIsIndex, |
| String[] prefixURIPairs, |
| boolean ignoreDefault) { |
| String expandedQName; |
| String prefix = getPrefix(lexicalQName); |
| String localName = (prefix != null) |
| ? lexicalQName.substring(prefix.length()+1) |
| : lexicalQName; |
| String uri = lookupStylesheetQNameNamespace(lexicalQName, |
| stylesheetNodeID, |
| ancestorNodeIDs, |
| prefixURIsIndex, |
| prefixURIPairs, |
| ignoreDefault); |
| |
| // Handle case when prefix is not resolved |
| if (prefix != null && prefix.length() != 0 |
| && (uri == null || uri.length() == 0)) { |
| runTimeError(NAMESPACE_PREFIX_ERR, prefix); |
| } |
| |
| if (uri.length() == 0) { |
| expandedQName = localName; |
| } else { |
| expandedQName = uri + ':' + localName; |
| } |
| |
| return expandedQName; |
| } |
| |
| /** |
| * 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; // not thread safe!! |
| public static String generatePrefix() { |
| 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 = "org.apache.xalan.xsltc.runtime.ErrorMessages"; |
| m_bundle = ResourceBundle.getBundle(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 StringBuffer result = new StringBuffer(); |
| |
| 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$"}); |
| |
| } |
| |
| //-- End utility functions |
| } |