001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.XPathContext;
004: import net.sf.saxon.om.Item;
005: import net.sf.saxon.om.FastStringBuffer;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.value.AtomicValue;
008: import net.sf.saxon.value.StringValue;
009:
010: public class Translate extends SystemFunction {
011:
012: /**
013: * Evaluate the function
014: */
015:
016: public Item evaluateItem(XPathContext context)
017: throws XPathException {
018:
019: AtomicValue sv = (AtomicValue) argument[0]
020: .evaluateItem(context);
021: if (sv == null) {
022: return StringValue.EMPTY_STRING;
023: }
024: ;
025: CharSequence s1 = sv.getStringValueCS();
026:
027: sv = (AtomicValue) argument[1].evaluateItem(context);
028: CharSequence s2 = sv.getStringValueCS();
029:
030: sv = (AtomicValue) argument[2].evaluateItem(context);
031: CharSequence s3 = sv.getStringValueCS();
032:
033: return StringValue.makeStringValue(translate(s1, s2, s3));
034: }
035:
036: /**
037: * Perform the translate function
038: */
039:
040: private static CharSequence translate(CharSequence s0,
041: CharSequence s1, CharSequence s2) {
042:
043: // check for surrogate pairs
044: int len0 = StringValue.getStringLength(s0);
045: int len1 = StringValue.getStringLength(s1);
046: int len2 = StringValue.getStringLength(s2);
047: if (s0.length() != len0 || s1.length() != len1
048: || s2.length() != len2) {
049: return slowTranslate(s0, s1, s2);
050: }
051: String st1 = s1.toString();
052: FastStringBuffer sb = new FastStringBuffer(s0.length());
053: int s2len = s2.length();
054: for (int i = 0; i < s0.length(); i++) {
055: char c = s0.charAt(i);
056: int j = st1.indexOf(c);
057: if (j < s2len) {
058: sb.append((j < 0 ? c : s2.charAt(j)));
059: }
060: }
061: return sb;
062: }
063:
064: /**
065: * Perform the translate function when surrogate pairs are in use
066: */
067:
068: private static CharSequence slowTranslate(CharSequence s0,
069: CharSequence s1, CharSequence s2) {
070: int[] a0 = StringValue.expand(s0);
071: int[] a1 = StringValue.expand(s1);
072: int[] a2 = StringValue.expand(s2);
073: StringBuffer sb = new StringBuffer(s0.length());
074: for (int i = 0; i < a0.length; i++) {
075: int c = a0[i];
076: int j = -1;
077: for (int test = 0; test < a1.length; test++) {
078: if (a1[test] == c) {
079: j = test;
080: break;
081: }
082: }
083: int newchar = -1;
084: if (j < 0) {
085: newchar = a0[i];
086: } else if (j < a2.length) {
087: newchar = a2[j];
088: } else {
089: // no new character
090: }
091:
092: if (newchar >= 0) {
093: if (newchar < 65536) {
094: sb.append((char) newchar);
095: } else { // output a surrogate pair
096: //To compute the numeric value of the character corresponding to a surrogate
097: //pair, use this formula (all numbers are hex):
098: //(FirstChar - D800) * 400 + (SecondChar - DC00) + 10000
099: newchar -= 65536;
100: sb.append((char) ((newchar / 1024) + 55296));
101: sb.append((char) ((newchar % 1024) + 56320));
102: }
103: }
104: }
105: return sb;
106: }
107:
108: }
109:
110: //
111: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
112: // you may not use this file except in compliance with the License. You may obtain a copy of the
113: // License at http://www.mozilla.org/MPL/
114: //
115: // Software distributed under the License is distributed on an "AS IS" basis,
116: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
117: // See the License for the specific language governing rights and limitations under the License.
118: //
119: // The Original Code is: all this file.
120: //
121: // The Initial Developer of the Original Code is Michael H. Kay.
122: //
123: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
124: //
125: // Contributor(s): none.
126: //
|