mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-08-07 10:42:55 +03:00
cleaning up Result Value Tree handling fixed a pair of implementations.
* libxslt/transform.c libxslt/variables.c libxslt/xsltInternals.h: cleaning up Result Value Tree handling * libexslt/functions.c libexslt/strings.c: fixed a pair of implementations. * tests/exslt/strings/Makefile.am tests/exslt/strings/tokenize.2.*: added Mark Vakoc test combining for-each and exslt:tokenize Daniel
This commit is contained in:
@@ -1,3 +1,12 @@
|
|||||||
|
Wed Apr 30 22:44:49 CEST 2003 Daniel Veillard <daniel@veillard.com>
|
||||||
|
|
||||||
|
* libxslt/transform.c libxslt/variables.c libxslt/xsltInternals.h:
|
||||||
|
cleaning up Result Value Tree handling
|
||||||
|
* libexslt/functions.c libexslt/strings.c: fixed a pair of
|
||||||
|
implementations.
|
||||||
|
* tests/exslt/strings/Makefile.am tests/exslt/strings/tokenize.2.*:
|
||||||
|
added Mark Vakoc test combining for-each and exslt:tokenize
|
||||||
|
|
||||||
Wed Apr 30 15:23:33 CEST 2003 Daniel Veillard <daniel@veillard.com>
|
Wed Apr 30 15:23:33 CEST 2003 Daniel Veillard <daniel@veillard.com>
|
||||||
|
|
||||||
* libxslt/transform.c: fixing bug #111755 when a template is
|
* libxslt/transform.c: fixing bug #111755 when a template is
|
||||||
|
@@ -511,21 +511,30 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
|||||||
* one or more child nodes), then the content of the
|
* one or more child nodes), then the content of the
|
||||||
* func:result element specifies the value.
|
* func:result element specifies the value.
|
||||||
*/
|
*/
|
||||||
xmlNodePtr container, oldInsert;
|
xmlNodePtr oldInsert;
|
||||||
|
xmlDocPtr container;
|
||||||
|
|
||||||
container = xmlNewDocNode (ctxt->output, NULL,
|
container = xsltCreateRVT(ctxt);
|
||||||
(const xmlChar *) "fake", NULL);
|
if (container == NULL) {
|
||||||
|
xsltGenericError(xsltGenericErrorContext,
|
||||||
|
"exsltFuncResultElem: out of memory\n");
|
||||||
|
data->error = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xsltRegisterTmpRVT(ctxt, container);
|
||||||
oldInsert = ctxt->insert;
|
oldInsert = ctxt->insert;
|
||||||
ctxt->insert = container;
|
ctxt->insert = (xmlNodePtr) container;
|
||||||
xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
|
xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
|
||||||
inst->children, NULL, NULL);
|
inst->children, NULL, NULL);
|
||||||
ctxt->insert = oldInsert;
|
ctxt->insert = oldInsert;
|
||||||
|
|
||||||
ret = xmlXPathNewValueTree(container);
|
ret = xmlXPathNewValueTree((xmlNodePtr) container);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
xsltGenericError(xsltGenericErrorContext,
|
xsltGenericError(xsltGenericErrorContext,
|
||||||
"exsltFuncResultElem: ret == NULL\n");
|
"exsltFuncResultElem: ret == NULL\n");
|
||||||
data->error = 1;
|
data->error = 1;
|
||||||
|
} else {
|
||||||
|
ret->boolval = 0; /* Freeing is not handled there anymore */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If the func:result element has empty content and does not
|
/* If the func:result element has empty content and does not
|
||||||
|
@@ -32,12 +32,12 @@
|
|||||||
static void
|
static void
|
||||||
exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
||||||
{
|
{
|
||||||
|
xsltTransformContextPtr tctxt;
|
||||||
xmlChar *str, *delimiters, *cur;
|
xmlChar *str, *delimiters, *cur;
|
||||||
const xmlChar *token, *delimiter;
|
const xmlChar *token, *delimiter;
|
||||||
xmlNodePtr node;
|
xmlNodePtr node;
|
||||||
xmlDocPtr container;
|
xmlDocPtr container;
|
||||||
|
xmlXPathObjectPtr ret = NULL;
|
||||||
xmlXPathObjectPtr ret;
|
|
||||||
|
|
||||||
if ((nargs < 1) || (nargs > 2)) {
|
if ((nargs < 1) || (nargs > 2)) {
|
||||||
xmlXPathSetArityError(ctxt);
|
xmlXPathSetArityError(ctxt);
|
||||||
@@ -61,17 +61,19 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return a result tree fragment */
|
/* Return a result tree fragment */
|
||||||
|
tctxt = xsltXPathGetTransformContext(ctxt);
|
||||||
|
if (tctxt == NULL) {
|
||||||
|
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||||
|
"exslt:tokenize : internal error tctxt == NULL\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
container = xmlNewDoc(NULL);
|
container = xsltCreateRVT(tctxt);
|
||||||
if (container != NULL) {
|
if (container != NULL) {
|
||||||
container->name =
|
xsltRegisterTmpRVT(tctxt, container);
|
||||||
(char *) xmlStrdup(BAD_CAST " fake node libxslt");
|
ret = xmlXPathNewNodeSet(NULL);
|
||||||
container->doc = container;
|
|
||||||
ret = xmlXPathNewValueTree((xmlNodePtr) container);
|
|
||||||
if (ret != NULL) {
|
if (ret != NULL) {
|
||||||
/* Tag the subtree for removal once consumed */
|
ret->boolval = 0; /* Freeing is not handled there anymore */
|
||||||
ret->boolval = 1;
|
|
||||||
ret->type = XPATH_XSLT_TREE;
|
|
||||||
for (cur = str, token = str; *cur != 0; cur++) {
|
for (cur = str, token = str; *cur != 0; cur++) {
|
||||||
for (delimiter = delimiters; *delimiter != 0; delimiter++) {
|
for (delimiter = delimiters; *delimiter != 0; delimiter++) {
|
||||||
if (*cur == *delimiter) {
|
if (*cur == *delimiter) {
|
||||||
@@ -83,6 +85,7 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
|||||||
node = xmlNewChild((xmlNodePtr) container, NULL,
|
node = xmlNewChild((xmlNodePtr) container, NULL,
|
||||||
(const xmlChar *) "token",
|
(const xmlChar *) "token",
|
||||||
token);
|
token);
|
||||||
|
xmlXPathNodeSetAddUnique(ret->nodesetval, node);
|
||||||
*cur = *delimiter;
|
*cur = *delimiter;
|
||||||
token = cur + 1;
|
token = cur + 1;
|
||||||
break;
|
break;
|
||||||
@@ -92,9 +95,11 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
|||||||
node =
|
node =
|
||||||
xmlNewChild((xmlNodePtr) container, NULL,
|
xmlNewChild((xmlNodePtr) container, NULL,
|
||||||
(const xmlChar *) "token", token);
|
(const xmlChar *) "token", token);
|
||||||
|
xmlXPathNodeSetAddUnique(ret->nodesetval, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
if (str != NULL)
|
if (str != NULL)
|
||||||
xmlFree(str);
|
xmlFree(str);
|
||||||
if (delimiters != NULL)
|
if (delimiters != NULL)
|
||||||
|
@@ -463,6 +463,7 @@ xsltFreeTransformContext(xsltTransformContextPtr ctxt) {
|
|||||||
xsltFreeGlobalVariables(ctxt);
|
xsltFreeGlobalVariables(ctxt);
|
||||||
xsltFreeDocuments(ctxt);
|
xsltFreeDocuments(ctxt);
|
||||||
xsltFreeCtxtExts(ctxt);
|
xsltFreeCtxtExts(ctxt);
|
||||||
|
xsltFreeRVTs(ctxt);
|
||||||
memset(ctxt, -1, sizeof(xsltTransformContext));
|
memset(ctxt, -1, sizeof(xsltTransformContext));
|
||||||
xmlFree(ctxt);
|
xmlFree(ctxt);
|
||||||
}
|
}
|
||||||
@@ -1251,18 +1252,6 @@ xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
|||||||
xsltTemplatePtr template;
|
xsltTemplatePtr template;
|
||||||
xmlNodePtr oldNode;
|
xmlNodePtr oldNode;
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) {
|
|
||||||
xmlNodePtr children;
|
|
||||||
|
|
||||||
children = node->children;
|
|
||||||
while (children != NULL) {
|
|
||||||
xsltProcessOneNode(ctxt, children, params);
|
|
||||||
children = children->next;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
template = xsltGetTemplate(ctxt, node, NULL);
|
template = xsltGetTemplate(ctxt, node, NULL);
|
||||||
/*
|
/*
|
||||||
* If no template is found, apply the default rule.
|
* If no template is found, apply the default rule.
|
||||||
@@ -1336,6 +1325,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
|||||||
xmlNodePtr oldInst = NULL;
|
xmlNodePtr oldInst = NULL;
|
||||||
xmlAttrPtr attrs;
|
xmlAttrPtr attrs;
|
||||||
int oldBase;
|
int oldBase;
|
||||||
|
xmlDocPtr tmpRVT = NULL;
|
||||||
|
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
||||||
@@ -1404,6 +1394,8 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
|||||||
start = xsltTimestamp();
|
start = xsltTimestamp();
|
||||||
profPush(ctxt, 0);
|
profPush(ctxt, 0);
|
||||||
}
|
}
|
||||||
|
tmpRVT = ctxt->tmpRVT;
|
||||||
|
ctxt->tmpRVT = NULL;
|
||||||
templPush(ctxt, templ);
|
templPush(ctxt, templ);
|
||||||
#ifdef WITH_XSLT_DEBUG_PROCESS
|
#ifdef WITH_XSLT_DEBUG_PROCESS
|
||||||
if (templ->name != NULL)
|
if (templ->name != NULL)
|
||||||
@@ -1694,6 +1686,19 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
|||||||
if (templ != NULL) {
|
if (templ != NULL) {
|
||||||
ctxt->varsBase = oldBase;
|
ctxt->varsBase = oldBase;
|
||||||
templPop(ctxt);
|
templPop(ctxt);
|
||||||
|
/*
|
||||||
|
* Free up all the unreferenced RVT
|
||||||
|
*/
|
||||||
|
if (ctxt->tmpRVT != NULL) {
|
||||||
|
xmlDocPtr tmp = ctxt->tmpRVT, next;
|
||||||
|
|
||||||
|
while (tmp != NULL) {
|
||||||
|
next = (xmlDocPtr) tmp->next;
|
||||||
|
xmlFreeDoc(tmp);
|
||||||
|
tmp = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctxt->tmpRVT = tmpRVT;
|
||||||
if (ctxt->profile) {
|
if (ctxt->profile) {
|
||||||
long spent, child, total, end;
|
long spent, child, total, end;
|
||||||
|
|
||||||
|
@@ -34,6 +34,106 @@
|
|||||||
#define WITH_XSLT_DEBUG_VARIABLE
|
#define WITH_XSLT_DEBUG_VARIABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* *
|
||||||
|
* Result Value Tree interfaces *
|
||||||
|
* *
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xsltCreateRVT:
|
||||||
|
* @ctxt: an XSLT transformation context
|
||||||
|
*
|
||||||
|
* Create a result value tree
|
||||||
|
*
|
||||||
|
* Returns the result value tree or NULL in case of error
|
||||||
|
*/
|
||||||
|
xmlDocPtr
|
||||||
|
xsltCreateRVT(xsltTransformContextPtr ctxt)
|
||||||
|
{
|
||||||
|
xmlDocPtr container;
|
||||||
|
|
||||||
|
if (ctxt == NULL) return(NULL);
|
||||||
|
|
||||||
|
container = xmlNewDoc(NULL);
|
||||||
|
if (container == NULL)
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
|
||||||
|
container->doc = container;
|
||||||
|
container->parent = NULL;
|
||||||
|
return(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xsltRegisterTmpRVT:
|
||||||
|
* @ctxt: an XSLT transformation context
|
||||||
|
* @RVT: a result value tree
|
||||||
|
*
|
||||||
|
* Register the result value tree for destruction at the end of the context
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success and -1 in case of error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
|
||||||
|
{
|
||||||
|
if ((ctxt == NULL) || (RVT == NULL)) return(-1);
|
||||||
|
|
||||||
|
RVT->next = (xmlNodePtr) ctxt->tmpRVT;
|
||||||
|
if (ctxt->tmpRVT != NULL)
|
||||||
|
ctxt->tmpRVT->prev = (xmlNodePtr) RVT;
|
||||||
|
ctxt->tmpRVT = RVT;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xsltRegisterPersistRVT:
|
||||||
|
* @ctxt: an XSLT transformation context
|
||||||
|
* @RVT: a result value tree
|
||||||
|
*
|
||||||
|
* Register the result value tree for destruction at the end of the processing
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success and -1 in case of error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT)
|
||||||
|
{
|
||||||
|
if ((ctxt == NULL) || (RVT == NULL)) return(-1);
|
||||||
|
|
||||||
|
RVT->next = (xmlNodePtr) ctxt->persistRVT;
|
||||||
|
if (ctxt->persistRVT != NULL)
|
||||||
|
ctxt->persistRVT->prev = (xmlNodePtr) RVT;
|
||||||
|
ctxt->persistRVT = RVT;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xsltFreeRVTs:
|
||||||
|
* @ctxt: an XSLT transformation context
|
||||||
|
*
|
||||||
|
* Free all the registered result value tree of the transformation
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
xsltFreeRVTs(xsltTransformContextPtr ctxt)
|
||||||
|
{
|
||||||
|
xmlDocPtr cur, next;
|
||||||
|
|
||||||
|
if (ctxt == NULL) return;
|
||||||
|
|
||||||
|
cur = ctxt->tmpRVT;
|
||||||
|
while (cur != NULL) {
|
||||||
|
next = (xmlDocPtr) cur->next;
|
||||||
|
xmlFreeDoc(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
cur = ctxt->persistRVT;
|
||||||
|
while (cur != NULL) {
|
||||||
|
next = (xmlDocPtr) cur->next;
|
||||||
|
xmlFreeDoc(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* *
|
* *
|
||||||
* Module interfaces *
|
* Module interfaces *
|
||||||
@@ -364,12 +464,13 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
|
|||||||
xmlNodePtr oldInsert;
|
xmlNodePtr oldInsert;
|
||||||
xmlDocPtr oldoutput;
|
xmlDocPtr oldoutput;
|
||||||
|
|
||||||
container = xmlNewDoc(NULL);
|
container = xsltCreateRVT(ctxt);
|
||||||
if (container == NULL)
|
if (container == NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
|
/*
|
||||||
container->doc = container;
|
* Tag the subtree for removal once consumed
|
||||||
container->parent = NULL;
|
*/
|
||||||
|
xsltRegisterTmpRVT(ctxt, container);
|
||||||
|
|
||||||
oldoutput = ctxt->output;
|
oldoutput = ctxt->output;
|
||||||
ctxt->output = container;
|
ctxt->output = container;
|
||||||
@@ -383,10 +484,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr elem,
|
|||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
result = xmlXPathNewCString("");
|
result = xmlXPathNewCString("");
|
||||||
} else {
|
} else {
|
||||||
/*
|
result->boolval = 0; /* Freeing is not handled there anymore */
|
||||||
* Tag the subtree for removal once consumed
|
|
||||||
*/
|
|
||||||
result->boolval = 1;
|
|
||||||
}
|
}
|
||||||
#ifdef WITH_XSLT_DEBUG_VARIABLE
|
#ifdef WITH_XSLT_DEBUG_VARIABLE
|
||||||
#ifdef LIBXML_DEBUG_ENABLED
|
#ifdef LIBXML_DEBUG_ENABLED
|
||||||
@@ -501,12 +599,13 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
|
|||||||
xmlNodePtr oldInsert;
|
xmlNodePtr oldInsert;
|
||||||
xmlDocPtr oldoutput;
|
xmlDocPtr oldoutput;
|
||||||
|
|
||||||
container = xmlNewDoc(NULL);
|
container = xsltCreateRVT(ctxt);
|
||||||
if (container == NULL)
|
if (container == NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
container->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
|
/*
|
||||||
container->doc = container;
|
* Tag the subtree for removal once consumed
|
||||||
container->parent = NULL;
|
*/
|
||||||
|
xsltRegisterTmpRVT(ctxt, container);
|
||||||
|
|
||||||
oldoutput = ctxt->output;
|
oldoutput = ctxt->output;
|
||||||
ctxt->output = container;
|
ctxt->output = container;
|
||||||
@@ -520,10 +619,7 @@ xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) {
|
|||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
result = xmlXPathNewCString("");
|
result = xmlXPathNewCString("");
|
||||||
} else {
|
} else {
|
||||||
/*
|
result->boolval = 0; /* Freeing is not handled there anymore */
|
||||||
* Tag the subtree for removal once consumed
|
|
||||||
*/
|
|
||||||
result->boolval = 1;
|
|
||||||
}
|
}
|
||||||
#ifdef WITH_XSLT_DEBUG_VARIABLE
|
#ifdef WITH_XSLT_DEBUG_VARIABLE
|
||||||
#ifdef LIBXML_DEBUG_ENABLED
|
#ifdef LIBXML_DEBUG_ENABLED
|
||||||
|
@@ -498,6 +498,12 @@ struct _xsltTransformContext {
|
|||||||
void * errctx; /* context for the error handler */
|
void * errctx; /* context for the error handler */
|
||||||
|
|
||||||
xsltSortFunc sortfunc; /* a ctxt specific sort routine */
|
xsltSortFunc sortfunc; /* a ctxt specific sort routine */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handling of temporary Result Value Tree
|
||||||
|
*/
|
||||||
|
xmlDocPtr tmpRVT; /* list of RVT without persistance */
|
||||||
|
xmlDocPtr persistRVT; /* list of persistant RVTs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -556,6 +562,15 @@ void xsltParseTemplateContent(xsltStylesheetPtr style,
|
|||||||
xmlNodePtr templ);
|
xmlNodePtr templ);
|
||||||
int xsltAllocateExtra (xsltStylesheetPtr style);
|
int xsltAllocateExtra (xsltStylesheetPtr style);
|
||||||
int xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt);
|
int xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt);
|
||||||
|
/*
|
||||||
|
* Extra functions for Result Value Trees
|
||||||
|
*/
|
||||||
|
xmlDocPtr xsltCreateRVT (xsltTransformContextPtr ctxt);
|
||||||
|
int xsltRegisterTmpRVT (xsltTransformContextPtr ctxt,
|
||||||
|
xmlDocPtr RVT);
|
||||||
|
int xsltRegisterPersistRVT (xsltTransformContextPtr ctxt,
|
||||||
|
xmlDocPtr RVT);
|
||||||
|
void xsltFreeRVTs (xsltTransformContextPtr ctxt);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -4,7 +4,8 @@ $(top_builddir)/xsltproc/xsltproc:
|
|||||||
@(cd ../../../xsltproc ; $(MAKE) xsltproc)
|
@(cd ../../../xsltproc ; $(MAKE) xsltproc)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
tokenize.1.xml tokenize.1.xsl tokenize.1.out
|
tokenize.1.xml tokenize.1.xsl tokenize.1.out \
|
||||||
|
tokenize.2.xml tokenize.2.xsl tokenize.2.out
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
||||||
|
2
tests/exslt/strings/tokenize.2.out
Normal file
2
tests/exslt/strings/tokenize.2.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<tok>This</tok><tok>is</tok><tok>strange</tok><tok>behavior</tok>
|
1
tests/exslt/strings/tokenize.2.xml
Normal file
1
tests/exslt/strings/tokenize.2.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<doc/>
|
13
tests/exslt/strings/tokenize.2.xsl
Normal file
13
tests/exslt/strings/tokenize.2.xsl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<xsl:stylesheet version="1.0"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:str="http://exslt.org/strings"
|
||||||
|
extension-element-prefixes="str">
|
||||||
|
|
||||||
|
<xsl:template match="/">
|
||||||
|
<xsl:for-each select="str:tokenize('This is strange behavior', ' ')" >
|
||||||
|
<tok><xsl:value-of select="."/></tok>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
Reference in New Issue
Block a user