mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-11-08 11:02:18 +03:00
added implementation of EXSLT - Strings. Currently implemented functins
* libexslt/Makefile.am libexslt/exslt.[ch] libexslt/strings.c: added implementation of EXSLT - Strings. Currently implemented functins are str:tokenize, str:align str:concat and str:padding. * configure.in tests/exslt/Makefile.am tests/exslt/strings/Makefile.am tests/exslt/strings/tokenize.1.*: added a test for the str:tokenize function.
This commit is contained in:
11
ChangeLog
11
ChangeLog
@@ -1,3 +1,14 @@
|
||||
Mon Sep 3 02:14:58 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
|
||||
|
||||
* libexslt/Makefile.am libexslt/exslt.[ch] libexslt/strings.c:
|
||||
added implementation of EXSLT - Strings.
|
||||
Currently implemented functins are str:tokenize, str:align
|
||||
str:concat and str:padding.
|
||||
* configure.in tests/exslt/Makefile.am
|
||||
tests/exslt/strings/Makefile.am
|
||||
tests/exslt/strings/tokenize.1.*: added a test for the
|
||||
str:tokenize function.
|
||||
|
||||
Fri Aug 31 13:51:53 CEST 2001 Daniel Veillard <daniel@veillard.com>
|
||||
|
||||
* libxslt/libxslt.4 libexslt/libexslt.4 libxslt/Makefile.am
|
||||
|
||||
@@ -252,6 +252,7 @@ tests/exslt/common/Makefile
|
||||
tests/exslt/functions/Makefile
|
||||
tests/exslt/math/Makefile
|
||||
tests/exslt/sets/Makefile
|
||||
tests/exslt/strings/Makefile
|
||||
doc/Makefile
|
||||
xslt-config
|
||||
libxslt.spec
|
||||
|
||||
@@ -17,7 +17,8 @@ libexslt_la_SOURCES = \
|
||||
common.c \
|
||||
math.c \
|
||||
sets.c \
|
||||
functions.c
|
||||
functions.c \
|
||||
strings.c
|
||||
|
||||
libexslt_la_LIBADD = $(EXTRA_LIBS)
|
||||
libexslt_la_LDFLAGS = -version-info @LIBEXSLT_VERSION_INFO@
|
||||
|
||||
@@ -26,5 +26,6 @@ exsltRegisterAll (void) {
|
||||
exsltMathRegister();
|
||||
exsltSetsRegister();
|
||||
exsltFuncRegister();
|
||||
exsltStrRegister();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,13 @@ LIBEXSLT_PUBLIC extern const int exsltLibxmlVersion;
|
||||
#define EXSLT_MATH_NAMESPACE ((const xmlChar *) "http://exslt.org/math")
|
||||
#define EXSLT_SETS_NAMESPACE ((const xmlChar *) "http://exslt.org/sets")
|
||||
#define EXSLT_FUNCTIONS_NAMESPACE ((const xmlChar *) "http://exslt.org/functions")
|
||||
#define EXSLT_STRINGS_NAMESPACE ((const xmlChar *) "http://exslt.org/strings")
|
||||
|
||||
void exsltCommonRegister (void);
|
||||
void exsltMathRegister (void);
|
||||
void exsltSetsRegister (void);
|
||||
void exsltFuncRegister (void);
|
||||
void exsltStrRegister (void);
|
||||
|
||||
void exsltRegisterAll (void);
|
||||
|
||||
|
||||
283
libexslt/strings.c
Normal file
283
libexslt/strings.c
Normal file
@@ -0,0 +1,283 @@
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/encoding.h>
|
||||
|
||||
#include <libxslt/xsltconfig.h>
|
||||
#include <libxslt/xsltutils.h>
|
||||
#include <libxslt/xsltInternals.h>
|
||||
#include <libxslt/extensions.h>
|
||||
|
||||
#include "exslt.h"
|
||||
|
||||
/**
|
||||
* exsltStrTokenizeFunction:
|
||||
* @ctxt: an XPath parser context
|
||||
* @nargs: the number of arguments
|
||||
*
|
||||
* Splits up a string and returns a node set of token elements, each
|
||||
* containing one token from the string.
|
||||
*/
|
||||
static void
|
||||
exsltStrTokenizeFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
xmlChar *str, *delimiters, *cur;
|
||||
const xmlChar *token, *delimiter;
|
||||
xmlNodePtr node;
|
||||
xmlDocPtr doc;
|
||||
xmlXPathObjectPtr ret;
|
||||
|
||||
if ((nargs < 1) || (nargs > 2)) {
|
||||
xmlXPathSetArityError (ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nargs == 2) {
|
||||
delimiters = xmlXPathPopString (ctxt);
|
||||
if (xmlXPathCheckError(ctxt))
|
||||
return;
|
||||
} else {
|
||||
delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
|
||||
}
|
||||
if (delimiters == NULL)
|
||||
return;
|
||||
|
||||
str = xmlXPathPopString (ctxt);
|
||||
if (xmlXPathCheckError(ctxt) || (str == NULL)) {
|
||||
xmlFree (delimiters);
|
||||
return;
|
||||
}
|
||||
|
||||
doc = xsltXPathGetTransformContext(ctxt)->output;
|
||||
ret = xmlXPathNewNodeSet (NULL);
|
||||
if (ret != NULL) {
|
||||
ret->boolval = 1;
|
||||
/*
|
||||
* This is a hack: token elements are added as children of a
|
||||
* fake element node. This is necessary to free them up
|
||||
* correctly when freeing the node-set.
|
||||
*/
|
||||
ret->user = (void *) xmlNewDocNode (doc, NULL,
|
||||
(const xmlChar *) "fake", NULL);
|
||||
if (ret->user == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (cur = str, token = str; *cur != 0; cur++) {
|
||||
for (delimiter = delimiters; *delimiter != 0; delimiter++) {
|
||||
if (*cur == *delimiter) {
|
||||
if (cur == token) {
|
||||
/* discard empty tokens */
|
||||
break;
|
||||
}
|
||||
*cur = 0;
|
||||
node = xmlNewDocNode (doc, NULL,
|
||||
(const xmlChar *) "token", token);
|
||||
*cur = *delimiter;
|
||||
token = cur + 1;
|
||||
|
||||
xmlAddChild ((xmlNodePtr) ret->user, node);
|
||||
xmlXPathNodeSetAdd (ret->nodesetval, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
node = xmlNewDocNode (doc, NULL, (const xmlChar *) "token", token);
|
||||
xmlAddChild ((xmlNodePtr) ret->user, node);
|
||||
xmlXPathNodeSetAdd (ret->nodesetval, node);
|
||||
|
||||
valuePush (ctxt, ret);
|
||||
ret = NULL; /* hack not to free ret later */
|
||||
|
||||
error:
|
||||
if (ret != NULL)
|
||||
xmlXPathFreeObject (ret);
|
||||
if (str != NULL)
|
||||
xmlFree(str);
|
||||
if (delimiters != NULL)
|
||||
xmlFree(delimiters);
|
||||
}
|
||||
|
||||
/**
|
||||
* exsltStrPaddingFunction:
|
||||
* @ctxt: an XPath parser context
|
||||
* @nargs: the number of arguments
|
||||
*
|
||||
* Creates a padding string of a certain length.
|
||||
*/
|
||||
static void
|
||||
exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
int number, str_len = 0;
|
||||
xmlChar *str, *ret = NULL, *tmp;
|
||||
|
||||
if ((nargs < 1) && (nargs > 2)) {
|
||||
xmlXPathSetArityError(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nargs == 2) {
|
||||
str = xmlXPathPopString(ctxt);
|
||||
str_len = xmlUTF8Strlen(str);
|
||||
}
|
||||
if (str_len == 0) {
|
||||
if (str != NULL) xmlFree(str);
|
||||
str = xmlStrdup((const xmlChar *) " ");
|
||||
str_len = 1;
|
||||
}
|
||||
|
||||
number = (int) xmlXPathPopNumber(ctxt);
|
||||
|
||||
if (number <= 0) {
|
||||
xmlXPathReturnEmptyString(ctxt);
|
||||
xmlFree(str);
|
||||
return;
|
||||
}
|
||||
|
||||
while (number >= str_len) {
|
||||
ret = xmlStrncat(ret, str, str_len);
|
||||
number -= str_len;
|
||||
}
|
||||
tmp = xmlUTF8Strndup (str, number);
|
||||
ret = xmlStrcat(ret, tmp);
|
||||
if (tmp != NULL)
|
||||
xmlFree (tmp);
|
||||
|
||||
xmlXPathReturnString(ctxt, ret);
|
||||
|
||||
if (str != NULL)
|
||||
xmlFree(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* exsltStrAlignFunction:
|
||||
* @ctxt: an XPath parser context
|
||||
* @nargs: the number of arguments
|
||||
*
|
||||
* Aligns a string within another string.
|
||||
*/
|
||||
static void
|
||||
exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
xmlChar *str, *padding, *alignment, *ret;
|
||||
int str_l, padding_l;
|
||||
|
||||
if ((nargs < 2) || (nargs > 3)) {
|
||||
xmlXPathSetArityError(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nargs == 3)
|
||||
alignment = xmlXPathPopString(ctxt);
|
||||
else
|
||||
alignment = NULL;
|
||||
|
||||
padding = xmlXPathPopString(ctxt);
|
||||
str = xmlXPathPopString(ctxt);
|
||||
|
||||
str_l = xmlUTF8Strlen (str);
|
||||
padding_l = xmlUTF8Strlen (padding);
|
||||
|
||||
if (str_l == padding_l) {
|
||||
xmlXPathReturnString (ctxt, str);
|
||||
xmlFree(padding);
|
||||
xmlFree(alignment);
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_l > padding_l) {
|
||||
ret = xmlUTF8Strndup (str, padding_l);
|
||||
} else {
|
||||
if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
|
||||
ret = xmlUTF8Strndup (padding, padding_l - str_l);
|
||||
ret = xmlStrcat (ret, str);
|
||||
} else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
|
||||
int left = (padding_l - str_l) / 2;
|
||||
int right_start;
|
||||
|
||||
ret = xmlUTF8Strndup (padding, left);
|
||||
ret = xmlStrcat (ret, str);
|
||||
|
||||
right_start = xmlUTF8Strsize (padding, left + str_l);
|
||||
ret = xmlStrcat (ret, padding + right_start);
|
||||
} else {
|
||||
int str_s;
|
||||
|
||||
str_s = xmlStrlen (str);
|
||||
ret = xmlStrdup (str);
|
||||
ret = xmlStrcat (ret, padding + str_s);
|
||||
}
|
||||
}
|
||||
|
||||
xmlXPathReturnString (ctxt, ret);
|
||||
|
||||
xmlFree(str);
|
||||
xmlFree(padding);
|
||||
xmlFree(alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* exsltStrConcatFunction:
|
||||
* @ctxt: an XPath parser context
|
||||
* @nargs: the number of arguments
|
||||
*
|
||||
* Takes a node set and returns the concatenation of the string values
|
||||
* of the nodes in that node set. If the node set is empty, it
|
||||
* returns an empty string.
|
||||
*/
|
||||
static void
|
||||
exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
xmlXPathObjectPtr obj;
|
||||
xmlChar *ret = NULL;
|
||||
int i;
|
||||
|
||||
if (nargs != 1) {
|
||||
xmlXPathSetArityError(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!xmlXPathStackIsNodeSet(ctxt)) {
|
||||
xmlXPathSetTypeError(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
obj = valuePop (ctxt);
|
||||
|
||||
if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
|
||||
xmlXPathReturnEmptyString(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
||||
xmlChar *tmp;
|
||||
tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
|
||||
|
||||
ret = xmlStrcat (ret, tmp);
|
||||
|
||||
xmlFree(tmp);
|
||||
}
|
||||
|
||||
xmlXPathFreeObject (obj);
|
||||
|
||||
xmlXPathReturnString(ctxt, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* exsltStrRegister:
|
||||
*
|
||||
* Registers the EXSLT - Strings module
|
||||
*/
|
||||
|
||||
void
|
||||
exsltStrRegister (void) {
|
||||
xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
|
||||
EXSLT_STRINGS_NAMESPACE,
|
||||
exsltStrTokenizeFunction);
|
||||
xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
|
||||
EXSLT_STRINGS_NAMESPACE,
|
||||
exsltStrPaddingFunction);
|
||||
xsltRegisterExtModuleFunction ((const xmlChar *) "align",
|
||||
EXSLT_STRINGS_NAMESPACE,
|
||||
exsltStrAlignFunction);
|
||||
xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
|
||||
EXSLT_STRINGS_NAMESPACE,
|
||||
exsltStrConcatFunction);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
SUBDIRS=common functions math sets
|
||||
SUBDIRS=common functions math sets strings
|
||||
|
||||
all:
|
||||
|
||||
|
||||
23
tests/exslt/strings/Makefile.am
Normal file
23
tests/exslt/strings/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
$(top_builddir)/xsltproc/xsltproc:
|
||||
@(cd ../../../xsltproc ; $(MAKE) xsltproc)
|
||||
|
||||
EXTRA_DIST = \
|
||||
tokenize.1.xml tokenize.1.xsl tokenize.1.out
|
||||
|
||||
all: test
|
||||
|
||||
test tests: $(top_builddir)/xsltproc/xsltproc
|
||||
@(echo > .memdump)
|
||||
@(for i in $(srcdir)/*.xsl ; do \
|
||||
name=`basename $$i .xsl` ; \
|
||||
if [ ! -f $(srcdir)/$$name.xml ] ; then continue ; fi ; \
|
||||
echo $$name.xml ; \
|
||||
$(top_builddir)/xsltproc/xsltproc $(srcdir)/$$name.xsl $(srcdir)/$$name.xml > $$name.res;\
|
||||
if [ ! -f $(srcdir)/$$name.out ] ; then cp $$name.res $(srcdir)/$$name.out ; \
|
||||
else if [ ! -s $$name.res ] ; then echo "Fatal error, no $$name.res\n" ; \
|
||||
else diff $(srcdir)/$$name.out $$name.res ; fi ; fi; \
|
||||
grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0" || true;\
|
||||
rm -f $$name.res ; \
|
||||
done)
|
||||
8
tests/exslt/strings/tokenize.1.out
Normal file
8
tests/exslt/strings/tokenize.1.out
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<out>;
|
||||
str:tokenize('2001-06-03T11:40:23', '-T:')
|
||||
<token>2001</token><token>06</token><token>03</token><token>11</token><token>40</token><token>23</token>;
|
||||
|
||||
str:tokenize('date math str')
|
||||
<token>date</token><token>math</token><token>str</token>;
|
||||
</out>
|
||||
5
tests/exslt/strings/tokenize.1.xml
Normal file
5
tests/exslt/strings/tokenize.1.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<doc>
|
||||
|
||||
</doc>
|
||||
17
tests/exslt/strings/tokenize.1.xsl
Normal file
17
tests/exslt/strings/tokenize.1.xsl
Normal file
@@ -0,0 +1,17 @@
|
||||
<?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="/">
|
||||
<out>;
|
||||
str:tokenize('2001-06-03T11:40:23', '-T:')
|
||||
<xsl:copy-of select="str:tokenize('2001-06-03T11:40:23', '-T:')"/>;
|
||||
|
||||
str:tokenize('date math str')
|
||||
<xsl:copy-of select="str:tokenize('date math str')"/>;
|
||||
</out>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
Reference in New Issue
Block a user