KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > functions > Substring


1 package net.sf.saxon.functions;
2 import net.sf.saxon.expr.Token;
3 import net.sf.saxon.expr.XPathContext;
4 import net.sf.saxon.om.Item;
5 import net.sf.saxon.trans.XPathException;
6 import net.sf.saxon.value.AtomicValue;
7 import net.sf.saxon.value.IntegerValue;
8 import net.sf.saxon.value.NumericValue;
9 import net.sf.saxon.value.StringValue;
10
11 /**
12  * This class implements the XPath substring() function
13  */

14
15 public class Substring extends SystemFunction {
16
17     /**
18     * Evaluate the function
19     */

20
21     public Item evaluateItem(XPathContext context) throws XPathException {
22
23         AtomicValue sv = (AtomicValue)argument[0].evaluateItem(context);
24         if (sv==null) {
25             sv = StringValue.EMPTY_STRING;
26         }
27         CharSequence JavaDoc s = sv.getStringValueCS();
28
29         AtomicValue a1 = (AtomicValue)argument[1].evaluateItem(context);
30         NumericValue a = (NumericValue)a1.getPrimitiveValue();
31
32         if (argument.length==2) {
33             return StringValue.makeStringValue(substring(s, a));
34         } else {
35             AtomicValue b2 = (AtomicValue)argument[2].evaluateItem(context);
36             NumericValue b = (NumericValue)b2.getPrimitiveValue();
37             return StringValue.makeStringValue(substring(s, a, b, context));
38         }
39     }
40
41     /**
42     * Implement substring function with two arguments.
43     */

44
45     private static CharSequence JavaDoc substring(CharSequence JavaDoc s, NumericValue start) {
46         int slength = s.length();
47
48         long lstart;
49         if (start instanceof IntegerValue) {
50             lstart = ((IntegerValue)start).longValue();
51         } else {
52             NumericValue rstart = start.round();
53             // We need to be careful to handle cases such as plus/minus infinity
54
if (rstart.compareTo(IntegerValue.ZERO) <= 0) {
55                 return s;
56             } else if (rstart.compareTo(new IntegerValue(slength)) > 0) {
57                 // this works even where the string contains surrogate pairs,
58
// because the Java length is always >= the XPath length
59
return "";
60             } else {
61                 try {
62                     lstart = rstart.longValue();
63                 } catch (XPathException err) {
64                     // this shouldn't happen unless the string length exceeds the bounds
65
// of a long
66
throw new AssertionError JavaDoc("string length out of permissible range");
67                 }
68             }
69         }
70
71         int pos=1;
72         int cpos=0;
73         while (cpos<slength) {
74             if (pos >= lstart) {
75                 return s.subSequence(cpos, s.length());
76             }
77
78             int ch = (int)s.charAt(cpos++);
79             if (ch<55296 || ch>56319) pos++; // don't count high surrogates, i.e. D800 to DBFF
80
}
81         return "";
82     }
83
84     /**
85     * Implement substring function with three arguments.
86     */

87
88     private static CharSequence JavaDoc substring(CharSequence JavaDoc s, NumericValue start, NumericValue len, XPathContext context) {
89         int slength = s.length();
90
91         long lstart;
92         if (start instanceof IntegerValue) {
93             lstart = ((IntegerValue)start).longValue();
94         } else {
95             start = start.round();
96             // We need to be careful to handle cases such as plus/minus infinity and NaN
97
if (start.compareTo(IntegerValue.ZERO) <= 0) {
98                 lstart = 0;
99             } else if (start.compareTo(new IntegerValue(slength)) > 0) {
100                 // this works even where the string contains surrogate pairs,
101
// because the Java length is always >= the XPath length
102
return "";
103             } else if (start.isNaN()) {
104                 return "";
105             } else {
106                 try {
107                     lstart = start.longValue();
108                 } catch (XPathException err) {
109                     // this shouldn't happen unless the string length exceeds the bounds
110
// of a long
111
throw new AssertionError JavaDoc("string length out of permissible range");
112                 }
113             }
114         }
115
116         NumericValue end;
117         try {
118             end = start.arithmetic(Token.PLUS, len.round(), context);
119         } catch (XPathException e) {
120             throw new AssertionError JavaDoc("Unexpected arithmetic failure in substring");
121         }
122         long lend;
123         if (end instanceof IntegerValue) {
124             lend = ((IntegerValue)end).longValue();
125         } else {
126             // We need to be careful to handle cases such as plus/minus infinity and NaN
127
if (end.compareTo(IntegerValue.ZERO) <= 0) {
128                 return "";
129             } else if (end.isNaN()) {
130                 return "";
131             } else if (end.compareTo(new IntegerValue(slength)) > 0) {
132                 // this works even where the string contains surrogate pairs,
133
// because the Java length is always >= the XPath length
134
lend = slength+1;
135             } else {
136                 try {
137                     lend = end.ceiling().longValue();
138                 } catch (XPathException err) {
139                     // this shouldn't happen unless the string length exceeds the bounds
140
// of a long
141
throw new AssertionError JavaDoc("string length out of permissible range");
142                 }
143             }
144         }
145
146         int jstart=-1;
147         int jend=-1;
148         int pos=1;
149         int cpos=0;
150         while (cpos<slength) {
151             if (pos >= lstart) {
152                 if (pos < lend) {
153                     if (jstart<0) {
154                         jstart = cpos;
155                     }
156                 } else {
157                     jend = cpos;
158                     break;
159                 }
160             }
161
162             int ch = (int)s.charAt(cpos++);
163             if (ch<55296 || ch>56319) pos++; // don't count high surrogates, i.e. D800 to DBFF
164
}
165         if (jstart<0 || jstart==jend) {
166             return "";
167         } else if (jend<0) {
168             return s.subSequence(jstart, s.length());
169         } else {
170             return s.subSequence(jstart, jend);
171         }
172     }
173 }
174
175
176
177 //
178
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
179
// you may not use this file except in compliance with the License. You may obtain a copy of the
180
// License at http://www.mozilla.org/MPL/
181
//
182
// Software distributed under the License is distributed on an "AS IS" basis,
183
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
184
// See the License for the specific language governing rights and limitations under the License.
185
//
186
// The Original Code is: all this file.
187
//
188
// The Initial Developer of the Original Code is Michael H. Kay.
189
//
190
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
191
//
192
// Contributor(s): none.
193
//
194
Popular Tags