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 ; 14 import java.util.regex.PatternSyntaxException ; 15 import java.util.regex.Matcher ; 16 17 18 22 23 public class Replace extends SystemFunction { 24 25 private Pattern regexp; 26 27 31 32 public Expression simplify(StaticContext env) throws XPathException { 33 Expression e = simplifyArguments(env); 34 35 if (!(e instanceof Value)) { 37 regexp = Matches.tryToCompile(argument, 1, 3); 38 39 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 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 replacement = arg2.getStringValueCS(); 65 checkReplacement(replacement, c); 66 67 Pattern re = regexp; 68 if (re == null) { 69 70 AtomicValue arg1 = (AtomicValue)argument[1].evaluateItem(c); 71 72 CharSequence 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 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 err) { 91 DynamicError de = new DynamicError(err); 92 de.setErrorCode("FORX0002"); 93 de.setXPathContext(c); 94 throw de; 95 } 96 97 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 input = arg0.getStringValue(); 104 Matcher matcher = re.matcher(input); 105 try { 106 String res = matcher.replaceAll(replacement.toString()); 107 return StringValue.makeStringValue(res); 108 } catch (IndexOutOfBoundsException e) { 109 int gps = matcher.groupCount(); 113 if (gps >= 9) { 114 throw e; 116 } 117 String r = replacement.toString(); 118 String f = "\\$[" + (gps+1) + "-9]"; 120 String rep = Pattern.compile(f).matcher(r).replaceAll(""); 121 String res = matcher.replaceAll(rep); 122 return StringValue.makeStringValue(res); 123 } 124 125 } 126 127 130 131 private void checkReplacement(CharSequence 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 | Popular Tags |