package client.net.sf.saxon.ce.functions; import client.net.sf.saxon.ce.expr.XPathContext; import client.net.sf.saxon.ce.om.Item; import client.net.sf.saxon.ce.regex.ARegularExpression; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.value.AtomicValue; import client.net.sf.saxon.ce.value.StringValue; /** * This class implements the replace() function for replacing * substrings that match a regular expression */ public class Replace extends SystemFunction { public Replace newInstance() { return new Replace(); } /** * Evaluate the function in a string context */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue arg0 = (AtomicValue) argument[0].evaluateItem(c); if (arg0 == null) { arg0 = StringValue.EMPTY_STRING; } AtomicValue arg2 = (AtomicValue) argument[2].evaluateItem(c); CharSequence replacement = arg2.getStringValueCS(); String msg = checkReplacement(replacement); if (msg != null) { dynamicError(msg, "FORX0004", c); } AtomicValue arg1 = (AtomicValue) argument[1].evaluateItem(c); CharSequence flags; if (argument.length == 3) { flags = ""; } else { AtomicValue arg3 = (AtomicValue) argument[3].evaluateItem(c); flags = arg3.getStringValueCS(); } try { ARegularExpression re = new ARegularExpression(arg1.getStringValueCS(), flags.toString(), "XP20", null); // check that it's not a pattern that matches "" if (re.matches("")) { dynamicError( "The regular expression in replace() must not be one that matches a zero-length string", "FORX0003", c); } String input = arg0.getStringValue(); CharSequence res = re.replace(input, replacement); return StringValue.makeStringValue(res); } catch (XPathException err) { XPathException de = new XPathException(err); de.setErrorCode("FORX0002"); de.setXPathContext(c); de.maybeSetLocation(getSourceLocator()); throw de; } } /** * Check the contents of the replacement string * * @param rep the replacement string * @return null if the string is OK, or an error message if not */ public static String checkReplacement(CharSequence rep) { for (int i = 0; i < rep.length(); i++) { char c = rep.charAt(i); if (c == '$') { if (i + 1 < rep.length()) { char next = rep.charAt(++i); if (next < '0' || next > '9') { return "Invalid replacement string in replace(): $ sign must be followed by digit 0-9"; } } else { return "Invalid replacement string in replace(): $ sign at end of string"; } } else if (c == '\\') { if (i + 1 < rep.length()) { char next = rep.charAt(++i); if (next != '\\' && next != '$') { return "Invalid replacement string in replace(): \\ character must be followed by \\ or $"; } } else { return "Invalid replacement string in replace(): \\ character at end of string"; } } } return null; } } // 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.