KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.functions;
2 import net.sf.saxon.expr.Expression;
3 import net.sf.saxon.expr.StaticContext;
4 import net.sf.saxon.expr.XPathContext;
5 import net.sf.saxon.om.Item;
6 import net.sf.saxon.trans.DynamicError;
7 import net.sf.saxon.trans.XPathException;
8 import net.sf.saxon.type.RegexTranslator;
9 import net.sf.saxon.value.AtomicValue;
10 import net.sf.saxon.value.StringValue;
11 import net.sf.saxon.value.Value;
12
13 import java.util.regex.Pattern JavaDoc;
14 import java.util.regex.PatternSyntaxException JavaDoc;
15 import java.util.regex.Matcher JavaDoc;
16
17
18 /**
19 * This class implements the replace() function for replacing
20 * substrings that match a regular expression
21 */

22
23 public class Replace extends SystemFunction {
24
25     private Pattern JavaDoc regexp;
26
27     /**
28     * Simplify and validate.
29     * This is a pure function so it can be simplified in advance if the arguments are known
30     */

31
32      public Expression simplify(StaticContext env) throws XPathException {
33         Expression e = simplifyArguments(env);
34
35         // compile the regular expression once if possible
36
if (!(e instanceof Value)) {
37             regexp = Matches.tryToCompile(argument, 1, 3);
38
39             // check that it's not a pattern that matches ""
40
if (regexp != null && regexp.matcher("").matches()) {
41                 DynamicError err = new DynamicError(
42                         "The regular expression must not be one that matches a zero-length string");
43                 err.setErrorCode("FORX0003");
44                 throw err;
45             }
46         }
47
48         return e;
49     }
50
51
52     /**
53     * Evaluate the function in a string context
54     */

55
56     public Item evaluateItem(XPathContext c) throws XPathException {
57
58         AtomicValue arg0 = (AtomicValue)argument[0].evaluateItem(c);
59         if (arg0==null) {
60             arg0 = StringValue.EMPTY_STRING;
61         }
62
63         AtomicValue arg2 = (AtomicValue)argument[2].evaluateItem(c);
64         CharSequence JavaDoc replacement = arg2.getStringValueCS();
65         checkReplacement(replacement, c);
66
67         Pattern JavaDoc re = regexp;
68         if (re == null) {
69
70             AtomicValue arg1 = (AtomicValue)argument[1].evaluateItem(c);
71
72             CharSequence JavaDoc flags;
73
74             if (argument.length == 3) {
75                 flags = "";
76             } else {
77                 AtomicValue arg3 = (AtomicValue)argument[3].evaluateItem(c);
78                 flags = arg3.getStringValueCS();
79             }
80
81             try {
82                 String JavaDoc javaRegex = RegexTranslator.translate(
83                         arg1.getStringValueCS(), true);
84                 re = Pattern.compile(javaRegex, Matches.setFlags(flags));
85             } catch (RegexTranslator.RegexSyntaxException err) {
86                 DynamicError de = new DynamicError(err);
87                 de.setErrorCode("FORX0002");
88                 de.setXPathContext(c);
89                 throw de;
90             } catch (PatternSyntaxException JavaDoc err) {
91                 DynamicError de = new DynamicError(err);
92                 de.setErrorCode("FORX0002");
93                 de.setXPathContext(c);
94                 throw de;
95             }
96
97             // check that it's not a pattern that matches ""
98
if (re.matcher("").matches()) {
99                 dynamicError(
100                         "The regular expression must not be one that matches a zero-length string", "FORX0003", c);
101             }
102         }
103         String JavaDoc input = arg0.getStringValue();
104         Matcher JavaDoc matcher = re.matcher(input);
105         try {
106             String JavaDoc res = matcher.replaceAll(replacement.toString());
107             return StringValue.makeStringValue(res);
108         } catch (IndexOutOfBoundsException JavaDoc e) {
109             // this occurs if the replacement string references a group $n and there are less than n
110
// capturing subexpressions in the regex. In this case we're supposed to replace $n by an
111
// empty string. We do this by modifying the replacement string.
112
int gps = matcher.groupCount();
113             if (gps >= 9) {
114                 // don't know what's gone wrong here
115
throw e;
116             }
117             String JavaDoc r = replacement.toString();
118             // remove occurrences of $n from the replacement string, if n is greater than the number of groups
119
String JavaDoc f = "\\$[" + (gps+1) + "-9]";
120             String JavaDoc rep = Pattern.compile(f).matcher(r).replaceAll("");
121             String JavaDoc res = matcher.replaceAll(rep);
122             return StringValue.makeStringValue(res);
123         }
124
125     }
126
127     /**
128     * Check the contents of the replacement string
129     */

130
131     private void checkReplacement(CharSequence JavaDoc rep, XPathContext context) throws XPathException {
132         for (int i=0; i<rep.length(); i++) {
133             char c = rep.charAt(i);
134             if (c == '$') {
135                 if (i+1 < rep.length()) {
136                     char next = rep.charAt(++i);
137                     if (next < '0' || next > '9') {
138                         dynamicError("Invalid replacement string in replace(): $ sign must be followed by digit 0-9",
139                                 "FORX0004", context);
140                     }
141                 } else {
142                     dynamicError("Invalid replacement string in replace(): $ sign at end of string",
143                             "FORX0004", context);
144                 }
145             } else if (c == '\\') {
146                 if (i+1 < rep.length()) {
147                     char next = rep.charAt(++i);
148                     if (next != '\\' && next != '$') {
149                         dynamicError("Invalid replacement string in replace(): \\ character must be followed by \\ or $",
150                                 "FORX0004", context);
151                     }
152                 } else {
153                     dynamicError("Invalid replacement string in replace(): \\ character at end of string",
154                             "FORX0004", context);
155                 }
156             }
157         }
158     }
159
160 }
161
162
163
164 //
165
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
166
// you may not use this file except in compliance with the License. You may obtain a copy of the
167
// License at http://www.mozilla.org/MPL/
168
//
169
// Software distributed under the License is distributed on an "AS IS" basis,
170
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
171
// See the License for the specific language governing rights and limitations under the License.
172
//
173
// The Original Code is: all this file.
174
//
175
// The Initial Developer of the Original Code is Michael H. Kay
176
//
177
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
178
//
179
// Contributor(s): none.
180
//
181
Popular Tags