15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * attrvt.c: Implementation of the XSL Transformation 1.0 engine
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *           attribute value template handling part.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * References:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   http://www.w3.org/TR/1999/REC-xslt-19991116
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Michael Kay "XSLT Programmer's Reference" pp 637-643
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Writing Multiple Output Files
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See Copyright for the status of this software.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * daniel@veillard.com
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IN_LIBXSLT
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "libxslt.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libxml/xmlmemory.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libxml/tree.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libxml/xpath.h>
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libxml/xpathInternals.h>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "xslt.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "xsltutils.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "xsltInternals.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "templates.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WITH_XSLT_DEBUG
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define WITH_XSLT_DEBUG_AVT
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_AVT_SEG 10
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct _xsltAttrVT xsltAttrVT;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef xsltAttrVT *xsltAttrVTPtr;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct _xsltAttrVT {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct _xsltAttrVT *next; /* next xsltAttrVT */
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nb_seg;		/* Number of segments */
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_seg;	/* max capacity before re-alloc needed */
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int strstart;	/* is the start a string */
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the namespaces in scope
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlNsPtr *nsList;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nsNr;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * the content is an alternate of string and xmlXPathCompExprPtr
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void *segments[MAX_AVT_SEG];
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltNewAttrVT:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @style:  a XSLT process context
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Build a new xsltAttrVT structure
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns the structure or NULL in case of error
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static xsltAttrVTPtr
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltNewAttrVT(xsltStylesheetPtr style) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xsltAttrVTPtr cur;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur = (xsltAttrVTPtr) xmlMalloc(sizeof(xsltAttrVT));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (cur == NULL) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xsltTransformError(NULL, style, NULL,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		"xsltNewAttrVTPtr : malloc failed\n");
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (style != NULL) style->errors++;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return(NULL);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(cur, 0, sizeof(xsltAttrVT));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur->nb_seg = 0;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur->max_seg = MAX_AVT_SEG;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur->strstart = 0;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur->next = style->attVTs;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Note: this pointer may be changed by a re-alloc within xsltCompileAttr,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * so that code may change the stylesheet pointer also!
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    style->attVTs = (xsltAttrVTPtr) cur;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return(cur);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltFreeAttrVT:
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @avt: pointer to an xsltAttrVT structure
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Free up the memory associated to the attribute value template
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltFreeAttrVT(xsltAttrVTPtr avt) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt == NULL) return;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt->strstart == 1) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0;i < avt->nb_seg; i += 2)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (avt->segments[i] != NULL)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xmlFree((xmlChar *) avt->segments[i]);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 1;i < avt->nb_seg; i += 2)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 0;i < avt->nb_seg; i += 2)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i = 1;i < avt->nb_seg; i += 2)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (avt->segments[i] != NULL)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xmlFree((xmlChar *) avt->segments[i]);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt->nsList != NULL)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xmlFree(avt->nsList);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlFree(avt);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltFreeAVTList:
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @avt: pointer to an list of AVT structures
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Free up the memory associated to the attribute value templates
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltFreeAVTList(void *avt) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (cur != NULL) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next = cur->next;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xsltFreeAttrVT(cur);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cur = next;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltSetAttrVTsegment:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @ avt: pointer to an xsltAttrVT structure
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @ val: the value to be set to the next available segment
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Within xsltCompileAttr there are several places where a value
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * needs to be added to the 'segments' array within the xsltAttrVT
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * structure, and at each place the allocated size may have to be
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * re-allocated.  This routine takes care of that situation.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns the avt pointer, which may have been changed by a re-alloc
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static xsltAttrVTPtr
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt->nb_seg >= avt->max_seg) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	avt = (xsltAttrVTPtr) xmlRealloc(avt, sizeof(xsltAttrVT) +
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    		avt->max_seg * sizeof(void *));
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (avt == NULL) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    return NULL;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *));
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	avt->max_seg += MAX_AVT_SEG;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    avt->segments[avt->nb_seg++] = val;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return avt;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltCompileAttr:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @style:  a XSLT process context
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @attr: the attribute coming from the stylesheet.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Precompile an attribute in a stylesheet, basically it checks if it is
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * an attrubute value template, and if yes establish some structures needed
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to process it at transformation time.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const xmlChar *str;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const xmlChar *cur;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlChar *ret = NULL;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlChar *expr = NULL;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xsltAttrVTPtr avt;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i = 0, lastavt = 0;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((style == NULL) || (attr == NULL) || (attr->children == NULL))
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((attr->children->type != XML_TEXT_NODE) ||
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (attr->children->next != NULL)) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xsltTransformError(NULL, style, attr->parent,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    "Attribute '%s': The content is expected to be a single text "
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    "node when compiling an AVT.\n", attr->name);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	style->errors++;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    str = attr->children->content;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((xmlStrchr(str, '{') == NULL) &&
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (xmlStrchr(str, '}') == NULL)) return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WITH_XSLT_DEBUG_AVT
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xsltGenericDebug(xsltGenericDebugContext,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    "Found AVT %s: %s\n", attr->name, str);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (attr->psvi != NULL) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WITH_XSLT_DEBUG_AVT
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xsltGenericDebug(xsltGenericDebugContext,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			"AVT %s: already compiled\n", attr->name);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    * Create a new AVT object.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    */
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    avt = xsltNewAttrVT(style);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt == NULL)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attr->psvi = avt;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    avt->nsList = xmlGetNsList(attr->doc, attr->parent);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt->nsList != NULL) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while (avt->nsList[i] != NULL)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    i++;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    avt->nsNr = i;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur = str;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*cur != 0) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (*cur == '{') {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (*(cur+1) == '{') {	/* escaped '{' */
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        cur++;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = xmlStrncat(ret, str, cur - str);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		cur++;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		str = cur;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		continue;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (*(cur+1) == '}') {	/* skip empty AVT */
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = xmlStrncat(ret, str, cur - str);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        cur += 2;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		str = cur;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		continue;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if ((ret != NULL) || (cur - str > 0)) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = xmlStrncat(ret, str, cur - str);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		str = cur;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (avt->nb_seg == 0)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    avt->strstart = 1;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    goto error;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = NULL;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		lastavt = 0;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    cur++;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    while ((*cur != 0) && (*cur != '}')) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Need to check for literal (bug539741) */
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if ((*cur == '\'') || (*cur == '"')) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    char delim = *(cur++);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    while ((*cur != 0) && (*cur != delim))
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			cur++;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    if (*cur != 0)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			cur++;	/* skip the ending delimiter */
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    cur++;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (*cur == 0) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        xsltTransformError(NULL, style, attr->parent,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     "Attribute '%s': The AVT has an unmatched '{'.\n",
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     attr->name);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		style->errors++;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto error;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    str++;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    expr = xmlStrndup(str, cur - str);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (expr == NULL) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/*
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		* TODO: What needs to be done here?
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*/
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        XSLT_TODO
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto error;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    } else {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xmlXPathCompExprPtr comp;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		comp = xsltXPathCompile(style, expr);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (comp == NULL) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    xsltTransformError(NULL, style, attr->parent,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 "Attribute '%s': Failed to compile the expression "
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			 "'%s' in the AVT.\n", attr->name, expr);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    style->errors++;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    goto error;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (avt->nb_seg == 0)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    avt->strstart = 0;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (lastavt == 1) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		        goto error;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    goto error;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		lastavt = 1;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		xmlFree(expr);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		expr = NULL;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    cur++;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    str = cur;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (*cur == '}') {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    cur++;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (*cur == '}') {	/* escaped '}' */
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = xmlStrncat(ret, str, cur - str);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		cur++;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		str = cur;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		continue;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    } else {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        xsltTransformError(NULL, style, attr->parent,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     "Attribute '%s': The AVT has an unmatched '}'.\n",
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		     attr->name);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto error;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    cur++;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((ret != NULL) || (cur - str > 0)) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ret = xmlStrncat(ret, str, cur - str);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	str = cur;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (avt->nb_seg == 0)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    avt->strstart = 1;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    goto error;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ret = NULL;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)error:
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (avt == NULL) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xsltTransformError(NULL, style, attr->parent,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		"xsltCompileAttr: malloc problem\n");
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (attr->psvi != avt) {  /* may have changed from realloc */
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            attr->psvi = avt;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    /*
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     * This is a "hack", but I can't see any clean method of
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     * doing it.  If a re-alloc has taken place, then the pointer
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     * for this AVT may have changed.  style->attVTs was set by
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     * xsltNewAttrVT, so it needs to be re-set to the new value!
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	     */
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    style->attVTs = avt;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ret != NULL)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xmlFree(ret);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (expr != NULL)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	xmlFree(expr);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * xsltEvalAVT:
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @ctxt: the XSLT transformation context
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @avt: the prevompiled attribute value template info
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @node: the node hosting the attribute
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Process the given AVT, and return the new string value.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns the computed string value or NULL, must be deallocated by the
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *         caller.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xmlChar *
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlChar *ret = NULL, *tmp;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmlXPathCompExprPtr comp;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xsltAttrVTPtr cur = (xsltAttrVTPtr) avt;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int i;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int str;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((ctxt == NULL) || (avt == NULL) || (node == NULL))
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return(NULL);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    str = cur->strstart;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0;i < cur->nb_seg;i++) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (str) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    comp = (xmlXPathCompExprPtr) cur->segments[i];
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (tmp != NULL) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	        if (ret != NULL) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    ret = xmlStrcat(ret, tmp);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    xmlFree(tmp);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    ret = tmp;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	str = !str;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return(ret);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
388