All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.functions.Translate Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.functions;



import net.sf.saxon.expr.Callable;
import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.StringLiteral;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.regex.UnicodeString;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.z.IntToIntHashMap;
import net.sf.saxon.z.IntToIntMap;

/**
 * Implement the XPath translate() function
 */

public class Translate extends SystemFunctionCall implements Callable {

    /*@Nullable*/ private IntToIntMap staticMap = null;
            // if the second and third arguments are known statically, we build a hash table for fast
            // lookup at run-time.

    /*@NotNull*/
    public Expression typeCheck(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException {
        Expression e = super.typeCheck(visitor, contextItemType);
        if (e == this && argument[1] instanceof StringLiteral && argument[2] instanceof StringLiteral) {
            // second and third arguments known statically: build an index
            staticMap = buildMap((StringValue)((StringLiteral)argument[1]).getValue(),
                    (StringValue)((StringLiteral)argument[2]).getValue());
        }
        return e;
    }

    /**
    * Evaluate the function
    */

    public StringValue evaluateItem(XPathContext context) throws XPathException {

        StringValue sv1 = (StringValue)argument[0].evaluateItem(context);
        if (sv1==null) {
            return StringValue.EMPTY_STRING;
        }

        if (staticMap != null) {
            CharSequence in = sv1.getStringValueCS();
            CharSequence sb = translateUsingMap(in, staticMap);
            return new StringValue(sb);
        }

        StringValue sv2 = (StringValue)argument[1].evaluateItem(context);

        StringValue sv3 = (StringValue)argument[2].evaluateItem(context);

        return StringValue.makeStringValue(translate(sv1, sv2, sv3));
    }

    /**
     * Get the translation map built at compile time if there is one
     */

    public IntToIntMap getStaticMap() {
        return staticMap;
    }

    /**
    * Perform the translate function
    */

    public static CharSequence translate(StringValue sv0, StringValue sv1, StringValue sv2) {

        // if any string contains surrogate pairs, expand everything to 32-bit characters
        if (sv0.containsSurrogatePairs() || sv1.containsSurrogatePairs() || sv2.containsSurrogatePairs()) {
            return translateUsingMap(sv0.getStringValueCS(), buildMap(sv1, sv2));
        }

        // if the size of the strings is above some threshold, use a hash map to avoid O(n*m) performance
        if (sv0.getStringLength() * sv1.getStringLength() > 1000) {
            // Cut-off point for building the map based on some simple measurements
            return translateUsingMap(sv0.getStringValueCS(), buildMap(sv1, sv2));
        }

        CharSequence cs0 = sv0.getStringValueCS();
        CharSequence cs1 = sv1.getStringValueCS();
        CharSequence cs2 = sv2.getStringValueCS();

        String st1 = cs1.toString();
        FastStringBuffer sb = new FastStringBuffer(cs0.length());
        int s2len = cs2.length();
        int s0len = cs0.length();
        for (int i=0; ia2.length()-1 ? -1 : a2.charAt(i)));
            }
        }
        return map;
    }

    /**
     * Implement the translate() function using an index built at compile time
     * @param in the string to be translated
     * @param map index built at compile time, mapping input characters to output characters. The map returns
     * -1 for a character that is to be deleted from the input string, Integer.MAX_VALUE for a character that is
     * to remain intact
     * @return the translated character string
     */

    public static CharSequence translateUsingMap(CharSequence in, IntToIntMap map) {
        UnicodeString us = UnicodeString.makeUnicodeString(in);
        int len = us.length();
        FastStringBuffer sb = new FastStringBuffer(len);
        for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy