[xslt] str:replace implementation



Please find attached an implementation of the exslt.org str:replace function and 7 test cases.

Documentation on the function can be found here:
  http://www.exslt.org/str/functions/replace/index.html

In that spec, I did not implement these last two sentences: "The longest search strings are replaced first. If a search string is empty, then the equivalently positioned replacement node is inserted between every character in the string." I felt the added code complexity and performance hit was not worth the impact at this time.

The other 11 sentences are implemented and add a useful capability to libexslt (imho)!

Daniel and Bill: I hope you are both doing well. I'm not subscribed to the xslt mailing list, and the mailman server seems to be busted with reagards to new subscriptions.

jr
diff --git a/libexslt/strings.c b/libexslt/strings.c
index c867f9c..e624d2b 100644
--- a/libexslt/strings.c
+++ b/libexslt/strings.c
@@ -495,6 +495,115 @@ exsltStrConcatFunction (xmlXPathParserCo
 }
 
 /**
+ * exsltStrReplaceInternal:
+ * @str: string to modify
+ * @searchStr: string to find
+ * @replaceStr: string to replace occurrences of searchStr
+ *
+ * Search and replace string function used by exsltStrReplaceFunction
+ */
+static xmlChar*
+exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr, 
+                        const xmlChar* replaceStr)
+{
+    const xmlChar *curr, *next;
+    xmlChar *ret = NULL;
+    int searchStrSize;
+
+    curr = str;
+    searchStrSize = xmlUTF8Strlen(searchStr);
+
+    do {
+      next = xmlStrstr(curr, searchStr);
+      if (next == NULL) {
+        ret = xmlStrcat (ret, curr);
+        break;
+      }
+
+      ret = xmlStrncat (ret, curr, next - curr);
+      ret = xmlStrcat (ret, replaceStr);
+      curr = next + searchStrSize;
+    } while (*curr != 0);
+
+    return ret;
+}
+/**
+ * exsltStrReplaceFunction:
+ * @ctxt: an XPath parser context
+ * @nargs: the number of arguments
+ *
+ * Takes a string, and two node sets and returns the string with all strings in 
+ * the first node set replaced by all strings in the second node set.
+ */
+static void
+exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
+    const xmlChar *str, *searchStr, *replaceStr = NULL;
+    xmlNodeSetPtr replaceSet = NULL, searchSet;
+    xmlChar *ret = NULL, *retSwap = NULL;
+    int i;
+
+    if (nargs  != 3) {
+      xmlXPathSetArityError(ctxt);
+      return;
+    }
+
+    /* pull out replace argument */
+    if (!xmlXPathStackIsNodeSet(ctxt)) {
+      replaceStr = xmlXPathPopString(ctxt);
+    }
+		else {
+      replaceSet = xmlXPathPopNodeSet(ctxt);
+      if (xmlXPathCheckError(ctxt)) {
+        xmlXPathSetTypeError(ctxt);
+        return;
+      }
+    }
+
+    /* behavior driven by search argument from here on */
+    if (!xmlXPathStackIsNodeSet(ctxt)) {
+      searchStr = xmlXPathPopString(ctxt);
+      str = xmlXPathPopString(ctxt);
+
+      if (replaceStr == NULL) {
+        xmlXPathSetTypeError(ctxt);
+        return;
+      }
+
+      ret = exsltStrReplaceInternal(str, searchStr, replaceStr);
+    }
+		else {
+
+      searchSet = xmlXPathPopNodeSet(ctxt);
+      if (searchSet == NULL || xmlXPathCheckError(ctxt)) {
+        xmlXPathSetTypeError(ctxt);
+        return;
+      }
+
+      str = xmlXPathPopString(ctxt);
+			ret = xmlStrdup(str);
+
+			for (i = 0; i < searchSet->nodeNr; i++) {
+
+				searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]);
+
+        if (replaceSet != NULL) {
+          replaceStr = NULL;
+          if (i <= replaceSet->nodeNr) {
+            replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]);
+          }
+        }
+				
+				retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
+				xmlFree(ret);
+				
+				ret = retSwap;
+			}
+		}
+
+    xmlXPathReturnString(ctxt, ret);
+}
+
+/**
  * exsltStrRegister:
  *
  * Registers the EXSLT - Strings module
@@ -523,4 +632,7 @@ exsltStrRegister (void) {
     xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
 				   EXSLT_STRINGS_NAMESPACE,
 				   exsltStrConcatFunction);
+    xsltRegisterExtModuleFunction ((const xmlChar *) "replace",
+				   EXSLT_STRINGS_NAMESPACE,
+				   exsltStrReplaceFunction);
 }
diff --git a/tests/exslt/strings/replace.1.out b/tests/exslt/strings/replace.1.out
new file mode 100644
index 0000000..076d110
--- /dev/null
+++ b/tests/exslt/strings/replace.1.out
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<out>;
+	str:replace('a, simple, list', ', ', '-')
+	a-simple-list
+
+	str:replace('a, simple, list', 'a, ', 'the ')
+	the simple, list
+
+	str:replace('a, simple, list', 'list', 'array')
+	a, simple, array
+
+	str:replace('a, simple, list', 'i', 'I')
+	a, sImple, lIst
+
+	str:replace('a, simple, list', ', ', '')
+	asimplelist
+
+	str:replace('fee, fi, fo, fum', $x, $y)
+	tee, eye, billow, a longer string
+
+	str:replace('fee, fi, fo, fum', $x, 'j')
+	j, j, j, j</out>
diff --git a/tests/exslt/strings/replace.1.xml b/tests/exslt/strings/replace.1.xml
new file mode 100644
index 0000000..6371161
--- /dev/null
+++ b/tests/exslt/strings/replace.1.xml
@@ -0,0 +1,12 @@
+<doc>
+	<strings>
+		<x>fee</x>
+		<x>fi</x>
+		<x>fo</x>
+		<x>fum</x>
+		<y>tee</y>
+		<y>eye</y>
+		<y>billow</y>
+		<y>a longer string</y>
+	</strings>
+</doc>
diff --git a/tests/exslt/strings/replace.1.xsl b/tests/exslt/strings/replace.1.xsl
new file mode 100644
index 0000000..0c9e86c
--- /dev/null
+++ b/tests/exslt/strings/replace.1.xsl
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+    xmlns:str="http://exslt.org/strings";
+    exclude-result-prefixes="str">
+
+<xsl:template match="/">
+	<xsl:variable name="x" select="doc/strings/x"/>
+	<xsl:variable name="y" select="doc/strings/y"/>
+
+<out>;
+	str:replace('a, simple, list', ', ', '-')
+	<xsl:copy-of select="str:replace('a, simple, list', ', ', '-')"/>
+
+	str:replace('a, simple, list', 'a, ', 'the ')
+	<xsl:copy-of select="str:replace('a, simple, list', 'a, ', 'the ')"/>
+
+	str:replace('a, simple, list', 'list', 'array')
+	<xsl:copy-of select="str:replace('a, simple, list', 'list', 'array')"/>
+
+	str:replace('a, simple, list', 'i', 'I')
+	<xsl:copy-of select="str:replace('a, simple, list', 'i', 'I')"/>
+
+	str:replace('a, simple, list', ', ', '')
+	<xsl:copy-of select="str:replace('a, simple, list', ', ', '')"/>
+
+	str:replace('fee, fi, fo, fum', $x, $y)
+	<xsl:copy-of select="str:replace('fee, fi, fo, fum', $x, $y)" />
+
+	str:replace('fee, fi, fo, fum', $x, 'j')
+	<xsl:copy-of select="str:replace('fee, fi, fo, fum', $x, 'j')" />
+
+</out>
+</xsl:template>
+
+</xsl:stylesheet>
begin:vcard
fn:Joel Reed
n:Reed;Joel
org:Development Dimensions International;E-Systems
adr;dom:;;1225 Washington Pike;Bridgeville;PA;15017
title:Manager, E-Products R&D
tel;work:412-257-3881
note;quoted-printable:Unleashing Executive Talent.  Hiring & Promoting The Best.=0D=0A=
	Developing Extraordinary Leaders.  Discover how at www.ddiworld.com
x-mozilla-html:FALSE
version:2.1
end:vcard



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]