| Index: third_party/libxslt/libxslt/xslt.c
|
| diff --git a/third_party/libxslt/libxslt/xslt.c b/third_party/libxslt/libxslt/xslt.c
|
| deleted file mode 100644
|
| index b367f9e9405c09389ffe584ec887dab1d94814f5..0000000000000000000000000000000000000000
|
| --- a/third_party/libxslt/libxslt/xslt.c
|
| +++ /dev/null
|
| @@ -1,7042 +0,0 @@
|
| -/*
|
| - * xslt.c: Implemetation of an XSL Transformation 1.0 engine
|
| - *
|
| - * Reference:
|
| - * XSLT specification
|
| - * http://www.w3.org/TR/1999/REC-xslt-19991116
|
| - *
|
| - * Associating Style Sheets with XML documents
|
| - * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629
|
| - *
|
| - * See Copyright for the status of this software.
|
| - *
|
| - * daniel@veillard.com
|
| - */
|
| -
|
| -#define IN_LIBXSLT
|
| -#include "libxslt.h"
|
| -
|
| -#include <string.h>
|
| -
|
| -#include <libxml/xmlmemory.h>
|
| -#include <libxml/parser.h>
|
| -#include <libxml/tree.h>
|
| -#include <libxml/valid.h>
|
| -#include <libxml/hash.h>
|
| -#include <libxml/uri.h>
|
| -#include <libxml/xmlerror.h>
|
| -#include <libxml/parserInternals.h>
|
| -#include <libxml/xpathInternals.h>
|
| -#include <libxml/xpath.h>
|
| -#include "xslt.h"
|
| -#include "xsltInternals.h"
|
| -#include "pattern.h"
|
| -#include "variables.h"
|
| -#include "namespaces.h"
|
| -#include "attributes.h"
|
| -#include "xsltutils.h"
|
| -#include "imports.h"
|
| -#include "keys.h"
|
| -#include "documents.h"
|
| -#include "extensions.h"
|
| -#include "preproc.h"
|
| -#include "extra.h"
|
| -#include "security.h"
|
| -
|
| -#ifdef WITH_XSLT_DEBUG
|
| -#define WITH_XSLT_DEBUG_PARSING
|
| -/* #define WITH_XSLT_DEBUG_BLANKS */
|
| -#endif
|
| -
|
| -const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA;
|
| -const int xsltLibxsltVersion = LIBXSLT_VERSION;
|
| -const int xsltLibxmlVersion = LIBXML_VERSION;
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -
|
| -const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE;
|
| -
|
| -#define XSLT_ELEMENT_CATEGORY_XSLT 0
|
| -#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
|
| -#define XSLT_ELEMENT_CATEGORY_LRE 2
|
| -
|
| -/*
|
| -* xsltLiteralResultMarker:
|
| -* Marker for Literal result elements, in order to avoid multiple attempts
|
| -* to recognize such elements in the stylesheet's tree.
|
| -* This marker is set on node->psvi during the initial traversal
|
| -* of a stylesheet's node tree.
|
| -*
|
| -const xmlChar *xsltLiteralResultMarker =
|
| - (const xmlChar *) "Literal Result Element";
|
| -*/
|
| -
|
| -/*
|
| -* xsltXSLTTextMarker:
|
| -* Marker for xsl:text elements. Used to recognize xsl:text elements
|
| -* for post-processing of the stylesheet's tree, where those
|
| -* elements are removed from the tree.
|
| -*/
|
| -const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element";
|
| -
|
| -/*
|
| -* xsltXSLTAttrMarker:
|
| -* Marker for XSLT attribute on Literal Result Elements.
|
| -*/
|
| -const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr";
|
| -
|
| -#endif
|
| -
|
| -#ifdef XSLT_LOCALE_WINAPI
|
| -extern xmlRMutexPtr xsltLocaleMutex;
|
| -#endif
|
| -/*
|
| - * Harmless but avoiding a problem when compiling against a
|
| - * libxml <= 2.3.11 without LIBXML_DEBUG_ENABLED
|
| - */
|
| -#ifndef LIBXML_DEBUG_ENABLED
|
| -double xmlXPathStringEvalNumber(const xmlChar *str);
|
| -#endif
|
| -/*
|
| - * Useful macros
|
| - */
|
| -
|
| -#ifdef IS_BLANK
|
| -#undef IS_BLANK
|
| -#endif
|
| -#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
|
| - ((c) == 0x0D))
|
| -
|
| -#ifdef IS_BLANK_NODE
|
| -#undef IS_BLANK_NODE
|
| -#endif
|
| -#define IS_BLANK_NODE(n) \
|
| - (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
|
| -
|
| -/**
|
| - * xsltParseContentError:
|
| - *
|
| - * @style: the stylesheet
|
| - * @node: the node where the error occured
|
| - *
|
| - * Compile-time error function.
|
| - */
|
| -static void
|
| -xsltParseContentError(xsltStylesheetPtr style,
|
| - xmlNodePtr node)
|
| -{
|
| - if ((style == NULL) || (node == NULL))
|
| - return;
|
| -
|
| - if (IS_XSLT_ELEM(node))
|
| - xsltTransformError(NULL, style, node,
|
| - "The XSLT-element '%s' is not allowed at this position.\n",
|
| - node->name);
|
| - else
|
| - xsltTransformError(NULL, style, node,
|
| - "The element '%s' is not allowed at this position.\n",
|
| - node->name);
|
| - style->errors++;
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -#else
|
| -/**
|
| - * exclPrefixPush:
|
| - * @style: the transformation stylesheet
|
| - * @value: the excluded namespace name to push on the stack
|
| - *
|
| - * Push an excluded namespace name on the stack
|
| - *
|
| - * Returns the new index in the stack or -1 if already present or
|
| - * in case of error
|
| - */
|
| -static int
|
| -exclPrefixPush(xsltStylesheetPtr style, xmlChar * value)
|
| -{
|
| - int i;
|
| -
|
| - if (style->exclPrefixMax == 0) {
|
| - style->exclPrefixMax = 4;
|
| - style->exclPrefixTab =
|
| - (xmlChar * *)xmlMalloc(style->exclPrefixMax *
|
| - sizeof(style->exclPrefixTab[0]));
|
| - if (style->exclPrefixTab == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
|
| - return (-1);
|
| - }
|
| - }
|
| - /* do not push duplicates */
|
| - for (i = 0;i < style->exclPrefixNr;i++) {
|
| - if (xmlStrEqual(style->exclPrefixTab[i], value))
|
| - return(-1);
|
| - }
|
| - if (style->exclPrefixNr >= style->exclPrefixMax) {
|
| - style->exclPrefixMax *= 2;
|
| - style->exclPrefixTab =
|
| - (xmlChar * *)xmlRealloc(style->exclPrefixTab,
|
| - style->exclPrefixMax *
|
| - sizeof(style->exclPrefixTab[0]));
|
| - if (style->exclPrefixTab == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
|
| - return (-1);
|
| - }
|
| - }
|
| - style->exclPrefixTab[style->exclPrefixNr] = value;
|
| - style->exclPrefix = value;
|
| - return (style->exclPrefixNr++);
|
| -}
|
| -/**
|
| - * exclPrefixPop:
|
| - * @style: the transformation stylesheet
|
| - *
|
| - * Pop an excluded prefix value from the stack
|
| - *
|
| - * Returns the stored excluded prefix value
|
| - */
|
| -static xmlChar *
|
| -exclPrefixPop(xsltStylesheetPtr style)
|
| -{
|
| - xmlChar *ret;
|
| -
|
| - if (style->exclPrefixNr <= 0)
|
| - return (0);
|
| - style->exclPrefixNr--;
|
| - if (style->exclPrefixNr > 0)
|
| - style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1];
|
| - else
|
| - style->exclPrefix = NULL;
|
| - ret = style->exclPrefixTab[style->exclPrefixNr];
|
| - style->exclPrefixTab[style->exclPrefixNr] = 0;
|
| - return (ret);
|
| -}
|
| -#endif
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Helper functions *
|
| - * *
|
| - ************************************************************************/
|
| -
|
| -static int initialized = 0;
|
| -/**
|
| - * xsltInit:
|
| - *
|
| - * Initializes the processor (e.g. registers built-in extensions,
|
| - * etc.)
|
| - */
|
| -void
|
| -xsltInit (void) {
|
| - if (initialized == 0) {
|
| - initialized = 1;
|
| -#ifdef XSLT_LOCALE_WINAPI
|
| - xsltLocaleMutex = xmlNewRMutex();
|
| -#endif
|
| - xsltRegisterAllExtras();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltUninit:
|
| - *
|
| - * Uninitializes the processor.
|
| - */
|
| -void
|
| -xsltUninit (void) {
|
| -#ifdef XSLT_LOCALE_WINAPI
|
| - xmlFreeRMutex(xsltLocaleMutex);
|
| - xsltLocaleMutex = NULL;
|
| -#endif
|
| - initialized = 0;
|
| -}
|
| -
|
| -/**
|
| - * xsltIsBlank:
|
| - * @str: a string
|
| - *
|
| - * Check if a string is ignorable
|
| - *
|
| - * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
|
| - */
|
| -int
|
| -xsltIsBlank(xmlChar *str) {
|
| - if (str == NULL)
|
| - return(1);
|
| - while (*str != 0) {
|
| - if (!(IS_BLANK(*str))) return(0);
|
| - str++;
|
| - }
|
| - return(1);
|
| -}
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Routines to handle XSLT data structures *
|
| - * *
|
| - ************************************************************************/
|
| -static xsltDecimalFormatPtr
|
| -xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name)
|
| -{
|
| - xsltDecimalFormatPtr self;
|
| - /* UTF-8 for 0x2030 */
|
| - static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0};
|
| -
|
| - self = xmlMalloc(sizeof(xsltDecimalFormat));
|
| - if (self != NULL) {
|
| - self->next = NULL;
|
| - self->nsUri = nsUri;
|
| - self->name = name;
|
| -
|
| - /* Default values */
|
| - self->digit = xmlStrdup(BAD_CAST("#"));
|
| - self->patternSeparator = xmlStrdup(BAD_CAST(";"));
|
| - self->decimalPoint = xmlStrdup(BAD_CAST("."));
|
| - self->grouping = xmlStrdup(BAD_CAST(","));
|
| - self->percent = xmlStrdup(BAD_CAST("%"));
|
| - self->permille = xmlStrdup(BAD_CAST(permille));
|
| - self->zeroDigit = xmlStrdup(BAD_CAST("0"));
|
| - self->minusSign = xmlStrdup(BAD_CAST("-"));
|
| - self->infinity = xmlStrdup(BAD_CAST("Infinity"));
|
| - self->noNumber = xmlStrdup(BAD_CAST("NaN"));
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -static void
|
| -xsltFreeDecimalFormat(xsltDecimalFormatPtr self)
|
| -{
|
| - if (self != NULL) {
|
| - if (self->digit)
|
| - xmlFree(self->digit);
|
| - if (self->patternSeparator)
|
| - xmlFree(self->patternSeparator);
|
| - if (self->decimalPoint)
|
| - xmlFree(self->decimalPoint);
|
| - if (self->grouping)
|
| - xmlFree(self->grouping);
|
| - if (self->percent)
|
| - xmlFree(self->percent);
|
| - if (self->permille)
|
| - xmlFree(self->permille);
|
| - if (self->zeroDigit)
|
| - xmlFree(self->zeroDigit);
|
| - if (self->minusSign)
|
| - xmlFree(self->minusSign);
|
| - if (self->infinity)
|
| - xmlFree(self->infinity);
|
| - if (self->noNumber)
|
| - xmlFree(self->noNumber);
|
| - if (self->name)
|
| - xmlFree(self->name);
|
| - xmlFree(self);
|
| - }
|
| -}
|
| -
|
| -static void
|
| -xsltFreeDecimalFormatList(xsltStylesheetPtr self)
|
| -{
|
| - xsltDecimalFormatPtr iter;
|
| - xsltDecimalFormatPtr tmp;
|
| -
|
| - if (self == NULL)
|
| - return;
|
| -
|
| - iter = self->decimalFormat;
|
| - while (iter != NULL) {
|
| - tmp = iter->next;
|
| - xsltFreeDecimalFormat(iter);
|
| - iter = tmp;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltDecimalFormatGetByName:
|
| - * @style: the XSLT stylesheet
|
| - * @name: the decimal-format name to find
|
| - *
|
| - * Find decimal-format by name
|
| - *
|
| - * Returns the xsltDecimalFormatPtr
|
| - */
|
| -xsltDecimalFormatPtr
|
| -xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name)
|
| -{
|
| - xsltDecimalFormatPtr result = NULL;
|
| -
|
| - if (name == NULL)
|
| - return style->decimalFormat;
|
| -
|
| - while (style != NULL) {
|
| - for (result = style->decimalFormat->next;
|
| - result != NULL;
|
| - result = result->next) {
|
| - if ((result->nsUri == NULL) && xmlStrEqual(name, result->name))
|
| - return result;
|
| - }
|
| - style = xsltNextImport(style);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -/**
|
| - * xsltDecimalFormatGetByQName:
|
| - * @style: the XSLT stylesheet
|
| - * @nsUri: the namespace URI of the QName
|
| - * @name: the local part of the QName
|
| - *
|
| - * Find decimal-format by QName
|
| - *
|
| - * Returns the xsltDecimalFormatPtr
|
| - */
|
| -xsltDecimalFormatPtr
|
| -xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri,
|
| - const xmlChar *name)
|
| -{
|
| - xsltDecimalFormatPtr result = NULL;
|
| -
|
| - if (name == NULL)
|
| - return style->decimalFormat;
|
| -
|
| - while (style != NULL) {
|
| - for (result = style->decimalFormat->next;
|
| - result != NULL;
|
| - result = result->next) {
|
| - if (xmlStrEqual(nsUri, result->nsUri) &&
|
| - xmlStrEqual(name, result->name))
|
| - return result;
|
| - }
|
| - style = xsltNextImport(style);
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -
|
| -/**
|
| - * xsltNewTemplate:
|
| - *
|
| - * Create a new XSLT Template
|
| - *
|
| - * Returns the newly allocated xsltTemplatePtr or NULL in case of error
|
| - */
|
| -static xsltTemplatePtr
|
| -xsltNewTemplate(void) {
|
| - xsltTemplatePtr cur;
|
| -
|
| - cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate));
|
| - if (cur == NULL) {
|
| - xsltTransformError(NULL, NULL, NULL,
|
| - "xsltNewTemplate : malloc failed\n");
|
| - return(NULL);
|
| - }
|
| - memset(cur, 0, sizeof(xsltTemplate));
|
| - cur->priority = XSLT_PAT_NO_PRIORITY;
|
| - return(cur);
|
| -}
|
| -
|
| -/**
|
| - * xsltFreeTemplate:
|
| - * @template: an XSLT template
|
| - *
|
| - * Free up the memory allocated by @template
|
| - */
|
| -static void
|
| -xsltFreeTemplate(xsltTemplatePtr template) {
|
| - if (template == NULL)
|
| - return;
|
| - if (template->match) xmlFree(template->match);
|
| -/*
|
| -* NOTE: @name and @nameURI are put into the string dict now.
|
| -* if (template->name) xmlFree(template->name);
|
| -* if (template->nameURI) xmlFree(template->nameURI);
|
| -*/
|
| -/*
|
| - if (template->mode) xmlFree(template->mode);
|
| - if (template->modeURI) xmlFree(template->modeURI);
|
| - */
|
| - if (template->inheritedNs) xmlFree(template->inheritedNs);
|
| -
|
| - /* free profiling data */
|
| - if (template->templCalledTab) xmlFree(template->templCalledTab);
|
| - if (template->templCountTab) xmlFree(template->templCountTab);
|
| -
|
| - memset(template, -1, sizeof(xsltTemplate));
|
| - xmlFree(template);
|
| -}
|
| -
|
| -/**
|
| - * xsltFreeTemplateList:
|
| - * @template: an XSLT template list
|
| - *
|
| - * Free up the memory allocated by all the elements of @template
|
| - */
|
| -static void
|
| -xsltFreeTemplateList(xsltTemplatePtr template) {
|
| - xsltTemplatePtr cur;
|
| -
|
| - while (template != NULL) {
|
| - cur = template;
|
| - template = template->next;
|
| - xsltFreeTemplate(cur);
|
| - }
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -
|
| -static void
|
| -xsltFreeNsAliasList(xsltNsAliasPtr item)
|
| -{
|
| - xsltNsAliasPtr tmp;
|
| -
|
| - while (item) {
|
| - tmp = item;
|
| - item = item->next;
|
| - xmlFree(tmp);
|
| - }
|
| - return;
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| -static void
|
| -xsltFreeNamespaceMap(xsltNsMapPtr item)
|
| -{
|
| - xsltNsMapPtr tmp;
|
| -
|
| - while (item) {
|
| - tmp = item;
|
| - item = item->next;
|
| - xmlFree(tmp);
|
| - }
|
| - return;
|
| -}
|
| -
|
| -static xsltNsMapPtr
|
| -xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
|
| - xmlDocPtr doc,
|
| - xmlNsPtr ns,
|
| - xmlNodePtr elem)
|
| -{
|
| - xsltNsMapPtr ret;
|
| -
|
| - if ((cctxt == NULL) || (doc == NULL) || (ns == NULL))
|
| - return(NULL);
|
| -
|
| - ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap));
|
| - if (ret == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Internal error: (xsltNewNamespaceMapItem) "
|
| - "memory allocation failed.\n");
|
| - return(NULL);
|
| - }
|
| - memset(ret, 0, sizeof(xsltNsMap));
|
| - ret->doc = doc;
|
| - ret->ns = ns;
|
| - ret->origNsName = ns->href;
|
| - /*
|
| - * Store the item at current stylesheet-level.
|
| - */
|
| - if (cctxt->psData->nsMap != NULL)
|
| - ret->next = cctxt->psData->nsMap;
|
| - cctxt->psData->nsMap = ret;
|
| -
|
| - return(ret);
|
| -}
|
| -#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
|
| -
|
| -/**
|
| - * xsltCompilerVarInfoFree:
|
| - * @cctxt: the compilation context
|
| - *
|
| - * Frees the list of information for vars/params.
|
| - */
|
| -static void
|
| -xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt)
|
| -{
|
| - xsltVarInfoPtr ivar = cctxt->ivars, ivartmp;
|
| -
|
| - while (ivar) {
|
| - ivartmp = ivar;
|
| - ivar = ivar->next;
|
| - xmlFree(ivartmp);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltCompilerCtxtFree:
|
| - *
|
| - * Free an XSLT compiler context.
|
| - */
|
| -static void
|
| -xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
|
| -{
|
| - if (cctxt == NULL)
|
| - return;
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "Freeing compilation context\n");
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### Max inodes: %d\n", cctxt->maxNodeInfos);
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### Max LREs : %d\n", cctxt->maxLREs);
|
| -#endif
|
| - /*
|
| - * Free node-infos.
|
| - */
|
| - if (cctxt->inodeList != NULL) {
|
| - xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList;
|
| - while (cur != NULL) {
|
| - tmp = cur;
|
| - cur = cur->next;
|
| - xmlFree(tmp);
|
| - }
|
| - }
|
| - if (cctxt->tmpList != NULL)
|
| - xsltPointerListFree(cctxt->tmpList);
|
| -#ifdef XSLT_REFACTORED_XPATHCOMP
|
| - if (cctxt->xpathCtxt != NULL)
|
| - xmlXPathFreeContext(cctxt->xpathCtxt);
|
| -#endif
|
| - if (cctxt->nsAliases != NULL)
|
| - xsltFreeNsAliasList(cctxt->nsAliases);
|
| -
|
| - if (cctxt->ivars)
|
| - xsltCompilerVarInfoFree(cctxt);
|
| -
|
| - xmlFree(cctxt);
|
| -}
|
| -
|
| -/**
|
| - * xsltCompilerCreate:
|
| - *
|
| - * Creates an XSLT compiler context.
|
| - *
|
| - * Returns the pointer to the created xsltCompilerCtxt or
|
| - * NULL in case of an internal error.
|
| - */
|
| -static xsltCompilerCtxtPtr
|
| -xsltCompilationCtxtCreate(xsltStylesheetPtr style) {
|
| - xsltCompilerCtxtPtr ret;
|
| -
|
| - ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt));
|
| - if (ret == NULL) {
|
| - xsltTransformError(NULL, style, NULL,
|
| - "xsltCompilerCreate: allocation of compiler "
|
| - "context failed.\n");
|
| - return(NULL);
|
| - }
|
| - memset(ret, 0, sizeof(xsltCompilerCtxt));
|
| -
|
| - ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
|
| - ret->tmpList = xsltPointerListCreate(20);
|
| - if (ret->tmpList == NULL) {
|
| - goto internal_err;
|
| - }
|
| -#ifdef XSLT_REFACTORED_XPATHCOMP
|
| - /*
|
| - * Create the XPath compilation context in order
|
| - * to speed up precompilation of XPath expressions.
|
| - */
|
| - ret->xpathCtxt = xmlXPathNewContext(NULL);
|
| - if (ret->xpathCtxt == NULL)
|
| - goto internal_err;
|
| -#endif
|
| -
|
| - return(ret);
|
| -
|
| -internal_err:
|
| - xsltCompilationCtxtFree(ret);
|
| - return(NULL);
|
| -}
|
| -
|
| -static void
|
| -xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first)
|
| -{
|
| - xsltEffectiveNsPtr tmp;
|
| -
|
| - while (first != NULL) {
|
| - tmp = first;
|
| - first = first->nextInStore;
|
| - xmlFree(tmp);
|
| - }
|
| -}
|
| -
|
| -static void
|
| -xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data)
|
| -{
|
| - if (data == NULL)
|
| - return;
|
| -
|
| - if (data->inScopeNamespaces != NULL) {
|
| - int i;
|
| - xsltNsListContainerPtr nsi;
|
| - xsltPointerListPtr list =
|
| - (xsltPointerListPtr) data->inScopeNamespaces;
|
| -
|
| - for (i = 0; i < list->number; i++) {
|
| - /*
|
| - * REVISIT TODO: Free info of in-scope namespaces.
|
| - */
|
| - nsi = (xsltNsListContainerPtr) list->items[i];
|
| - if (nsi->list != NULL)
|
| - xmlFree(nsi->list);
|
| - xmlFree(nsi);
|
| - }
|
| - xsltPointerListFree(list);
|
| - data->inScopeNamespaces = NULL;
|
| - }
|
| -
|
| - if (data->exclResultNamespaces != NULL) {
|
| - int i;
|
| - xsltPointerListPtr list = (xsltPointerListPtr)
|
| - data->exclResultNamespaces;
|
| -
|
| - for (i = 0; i < list->number; i++)
|
| - xsltPointerListFree((xsltPointerListPtr) list->items[i]);
|
| -
|
| - xsltPointerListFree(list);
|
| - data->exclResultNamespaces = NULL;
|
| - }
|
| -
|
| - if (data->extElemNamespaces != NULL) {
|
| - xsltPointerListPtr list = (xsltPointerListPtr)
|
| - data->extElemNamespaces;
|
| - int i;
|
| -
|
| - for (i = 0; i < list->number; i++)
|
| - xsltPointerListFree((xsltPointerListPtr) list->items[i]);
|
| -
|
| - xsltPointerListFree(list);
|
| - data->extElemNamespaces = NULL;
|
| - }
|
| - if (data->effectiveNs) {
|
| - xsltLREEffectiveNsNodesFree(data->effectiveNs);
|
| - data->effectiveNs = NULL;
|
| - }
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - xsltFreeNamespaceMap(data->nsMap);
|
| -#endif
|
| - xmlFree(data);
|
| -}
|
| -
|
| -static xsltPrincipalStylesheetDataPtr
|
| -xsltNewPrincipalStylesheetData(void)
|
| -{
|
| - xsltPrincipalStylesheetDataPtr ret;
|
| -
|
| - ret = (xsltPrincipalStylesheetDataPtr)
|
| - xmlMalloc(sizeof(xsltPrincipalStylesheetData));
|
| - if (ret == NULL) {
|
| - xsltTransformError(NULL, NULL, NULL,
|
| - "xsltNewPrincipalStylesheetData: memory allocation failed.\n");
|
| - return(NULL);
|
| - }
|
| - memset(ret, 0, sizeof(xsltPrincipalStylesheetData));
|
| -
|
| - /*
|
| - * Global list of in-scope namespaces.
|
| - */
|
| - ret->inScopeNamespaces = xsltPointerListCreate(-1);
|
| - if (ret->inScopeNamespaces == NULL)
|
| - goto internal_err;
|
| - /*
|
| - * Global list of excluded result ns-decls.
|
| - */
|
| - ret->exclResultNamespaces = xsltPointerListCreate(-1);
|
| - if (ret->exclResultNamespaces == NULL)
|
| - goto internal_err;
|
| - /*
|
| - * Global list of extension instruction namespace names.
|
| - */
|
| - ret->extElemNamespaces = xsltPointerListCreate(-1);
|
| - if (ret->extElemNamespaces == NULL)
|
| - goto internal_err;
|
| -
|
| - return(ret);
|
| -
|
| -internal_err:
|
| -
|
| - return(NULL);
|
| -}
|
| -
|
| -#endif
|
| -
|
| -/**
|
| - * xsltNewStylesheet:
|
| - *
|
| - * Create a new XSLT Stylesheet
|
| - *
|
| - * Returns the newly allocated xsltStylesheetPtr or NULL in case of error
|
| - */
|
| -xsltStylesheetPtr
|
| -xsltNewStylesheet(void) {
|
| - xsltStylesheetPtr ret = NULL;
|
| -
|
| - ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet));
|
| - if (ret == NULL) {
|
| - xsltTransformError(NULL, NULL, NULL,
|
| - "xsltNewStylesheet : malloc failed\n");
|
| - goto internal_err;
|
| - }
|
| - memset(ret, 0, sizeof(xsltStylesheet));
|
| -
|
| - ret->omitXmlDeclaration = -1;
|
| - ret->standalone = -1;
|
| - ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL);
|
| - ret->indent = -1;
|
| - ret->errors = 0;
|
| - ret->warnings = 0;
|
| - ret->exclPrefixNr = 0;
|
| - ret->exclPrefixMax = 0;
|
| - ret->exclPrefixTab = NULL;
|
| - ret->extInfos = NULL;
|
| - ret->extrasNr = 0;
|
| - ret->internalized = 1;
|
| - ret->literal_result = 0;
|
| - ret->forwards_compatible = 0;
|
| - ret->dict = xmlDictCreate();
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "creating dictionary for stylesheet\n");
|
| -#endif
|
| -
|
| - xsltInit();
|
| -
|
| - return(ret);
|
| -
|
| -internal_err:
|
| - if (ret != NULL)
|
| - xsltFreeStylesheet(ret);
|
| - return(NULL);
|
| -}
|
| -
|
| -/**
|
| - * xsltAllocateExtra:
|
| - * @style: an XSLT stylesheet
|
| - *
|
| - * Allocate an extra runtime information slot statically while compiling
|
| - * the stylesheet and return its number
|
| - *
|
| - * Returns the number of the slot
|
| - */
|
| -int
|
| -xsltAllocateExtra(xsltStylesheetPtr style)
|
| -{
|
| - return(style->extrasNr++);
|
| -}
|
| -
|
| -/**
|
| - * xsltAllocateExtraCtxt:
|
| - * @ctxt: an XSLT transformation context
|
| - *
|
| - * Allocate an extra runtime information slot at run-time
|
| - * and return its number
|
| - * This make sure there is a slot ready in the transformation context
|
| - *
|
| - * Returns the number of the slot
|
| - */
|
| -int
|
| -xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt)
|
| -{
|
| - if (ctxt->extrasNr >= ctxt->extrasMax) {
|
| - int i;
|
| - if (ctxt->extrasNr == 0) {
|
| - ctxt->extrasMax = 20;
|
| - ctxt->extras = (xsltRuntimeExtraPtr)
|
| - xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra));
|
| - if (ctxt->extras == NULL) {
|
| - xsltTransformError(ctxt, NULL, NULL,
|
| - "xsltAllocateExtraCtxt: out of memory\n");
|
| - return(0);
|
| - }
|
| - for (i = 0;i < ctxt->extrasMax;i++) {
|
| - ctxt->extras[i].info = NULL;
|
| - ctxt->extras[i].deallocate = NULL;
|
| - ctxt->extras[i].val.ptr = NULL;
|
| - }
|
| -
|
| - } else {
|
| - xsltRuntimeExtraPtr tmp;
|
| -
|
| - ctxt->extrasMax += 100;
|
| - tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras,
|
| - ctxt->extrasMax * sizeof(xsltRuntimeExtra));
|
| - if (tmp == NULL) {
|
| - xsltTransformError(ctxt, NULL, NULL,
|
| - "xsltAllocateExtraCtxt: out of memory\n");
|
| - return(0);
|
| - }
|
| - ctxt->extras = tmp;
|
| - for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) {
|
| - ctxt->extras[i].info = NULL;
|
| - ctxt->extras[i].deallocate = NULL;
|
| - ctxt->extras[i].val.ptr = NULL;
|
| - }
|
| - }
|
| - }
|
| - return(ctxt->extrasNr++);
|
| -}
|
| -
|
| -/**
|
| - * xsltFreeStylesheetList:
|
| - * @style: an XSLT stylesheet list
|
| - *
|
| - * Free up the memory allocated by the list @style
|
| - */
|
| -static void
|
| -xsltFreeStylesheetList(xsltStylesheetPtr style) {
|
| - xsltStylesheetPtr next;
|
| -
|
| - while (style != NULL) {
|
| - next = style->next;
|
| - xsltFreeStylesheet(style);
|
| - style = next;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltCleanupStylesheetTree:
|
| - *
|
| - * @doc: the document-node
|
| - * @node: the element where the stylesheet is rooted at
|
| - *
|
| - * Actually @node need not be the document-element, but
|
| - * currently Libxslt does not support embedded stylesheets.
|
| - *
|
| - * Returns 0 if OK, -1 on API or internal errors.
|
| - */
|
| -static int
|
| -xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED,
|
| - xmlNodePtr rootElem ATTRIBUTE_UNUSED)
|
| -{
|
| -#if 0 /* TODO: Currently disabled, since probably not needed. */
|
| - xmlNodePtr cur;
|
| -
|
| - if ((doc == NULL) || (rootElem == NULL) ||
|
| - (rootElem->type != XML_ELEMENT_NODE) ||
|
| - (doc != rootElem->doc))
|
| - return(-1);
|
| -
|
| - /*
|
| - * Cleanup was suggested by Aleksey Sanin:
|
| - * Clear the PSVI field to avoid problems if the
|
| - * node-tree of the stylesheet is intended to be used for
|
| - * further processing by the user (e.g. for compiling it
|
| - * once again - although not recommended).
|
| - */
|
| -
|
| - cur = rootElem;
|
| - while (cur != NULL) {
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - /*
|
| - * Clear the PSVI field.
|
| - */
|
| - cur->psvi = NULL;
|
| - if (cur->children) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - }
|
| -
|
| -leave_node:
|
| - if (cur == rootElem)
|
| - break;
|
| - if (cur->next != NULL)
|
| - cur = cur->next;
|
| - else {
|
| - cur = cur->parent;
|
| - if (cur == NULL)
|
| - break;
|
| - goto leave_node;
|
| - }
|
| - }
|
| -#endif /* #if 0 */
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltFreeStylesheet:
|
| - * @style: an XSLT stylesheet
|
| - *
|
| - * Free up the memory allocated by @style
|
| - */
|
| -void
|
| -xsltFreeStylesheet(xsltStylesheetPtr style)
|
| -{
|
| - if (style == NULL)
|
| - return;
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| - /*
|
| - * Start with a cleanup of the main stylesheet's doc.
|
| - */
|
| - if ((style->principal == style) && (style->doc))
|
| - xsltCleanupStylesheetTree(style->doc,
|
| - xmlDocGetRootElement(style->doc));
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - /*
|
| - * Restore changed ns-decls before freeing the document.
|
| - */
|
| - if ((style->doc != NULL) &&
|
| - XSLT_HAS_INTERNAL_NSMAP(style))
|
| - {
|
| - xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style),
|
| - style->doc);
|
| - }
|
| -#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
|
| -#else
|
| - /*
|
| - * Start with a cleanup of the main stylesheet's doc.
|
| - */
|
| - if ((style->parent == NULL) && (style->doc))
|
| - xsltCleanupStylesheetTree(style->doc,
|
| - xmlDocGetRootElement(style->doc));
|
| -#endif /* XSLT_REFACTORED */
|
| -
|
| - xsltFreeKeys(style);
|
| - xsltFreeExts(style);
|
| - xsltFreeTemplateHashes(style);
|
| - xsltFreeDecimalFormatList(style);
|
| - xsltFreeTemplateList(style->templates);
|
| - xsltFreeAttributeSetsHashes(style);
|
| - xsltFreeNamespaceAliasHashes(style);
|
| - xsltFreeStylePreComps(style);
|
| - /*
|
| - * Free documents of all included stylsheet modules of this
|
| - * stylesheet level.
|
| - */
|
| - xsltFreeStyleDocuments(style);
|
| - /*
|
| - * TODO: Best time to shutdown extension stuff?
|
| - */
|
| - xsltShutdownExts(style);
|
| -
|
| - if (style->variables != NULL)
|
| - xsltFreeStackElemList(style->variables);
|
| - if (style->cdataSection != NULL)
|
| - xmlHashFree(style->cdataSection, NULL);
|
| - if (style->stripSpaces != NULL)
|
| - xmlHashFree(style->stripSpaces, NULL);
|
| - if (style->nsHash != NULL)
|
| - xmlHashFree(style->nsHash, NULL);
|
| - if (style->exclPrefixTab != NULL)
|
| - xmlFree(style->exclPrefixTab);
|
| - if (style->method != NULL)
|
| - xmlFree(style->method);
|
| - if (style->methodURI != NULL)
|
| - xmlFree(style->methodURI);
|
| - if (style->version != NULL)
|
| - xmlFree(style->version);
|
| - if (style->encoding != NULL)
|
| - xmlFree(style->encoding);
|
| - if (style->doctypePublic != NULL)
|
| - xmlFree(style->doctypePublic);
|
| - if (style->doctypeSystem != NULL)
|
| - xmlFree(style->doctypeSystem);
|
| - if (style->mediaType != NULL)
|
| - xmlFree(style->mediaType);
|
| - if (style->attVTs)
|
| - xsltFreeAVTList(style->attVTs);
|
| - if (style->imports != NULL)
|
| - xsltFreeStylesheetList(style->imports);
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| - /*
|
| - * If this is the principal stylesheet, then
|
| - * free its internal data.
|
| - */
|
| - if (style->principal == style) {
|
| - if (style->principalData) {
|
| - xsltFreePrincipalStylesheetData(style->principalData);
|
| - style->principalData = NULL;
|
| - }
|
| - }
|
| -#endif
|
| - /*
|
| - * Better to free the main document of this stylesheet level
|
| - * at the end - so here.
|
| - */
|
| - if (style->doc != NULL) {
|
| - xmlFreeDoc(style->doc);
|
| - }
|
| -
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "freeing dictionary from stylesheet\n");
|
| -#endif
|
| - xmlDictFree(style->dict);
|
| -
|
| - memset(style, -1, sizeof(xsltStylesheet));
|
| - xmlFree(style);
|
| -}
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Parsing of an XSLT Stylesheet *
|
| - * *
|
| - ************************************************************************/
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| - /*
|
| - * This is now performed in an optimized way in xsltParseXSLTTemplate.
|
| - */
|
| -#else
|
| -/**
|
| - * xsltGetInheritedNsList:
|
| - * @style: the stylesheet
|
| - * @template: the template
|
| - * @node: the current node
|
| - *
|
| - * Search all the namespace applying to a given element except the ones
|
| - * from excluded output prefixes currently in scope. Initialize the
|
| - * template inheritedNs list with it.
|
| - *
|
| - * Returns the number of entries found
|
| - */
|
| -static int
|
| -xsltGetInheritedNsList(xsltStylesheetPtr style,
|
| - xsltTemplatePtr template,
|
| - xmlNodePtr node)
|
| -{
|
| - xmlNsPtr cur;
|
| - xmlNsPtr *ret = NULL;
|
| - int nbns = 0;
|
| - int maxns = 10;
|
| - int i;
|
| -
|
| - if ((style == NULL) || (template == NULL) || (node == NULL) ||
|
| - (template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
|
| - return(0);
|
| - while (node != NULL) {
|
| - if (node->type == XML_ELEMENT_NODE) {
|
| - cur = node->nsDef;
|
| - while (cur != NULL) {
|
| - if (xmlStrEqual(cur->href, XSLT_NAMESPACE))
|
| - goto skip_ns;
|
| -
|
| - if ((cur->prefix != NULL) &&
|
| - (xsltCheckExtPrefix(style, cur->prefix)))
|
| - goto skip_ns;
|
| - /*
|
| - * Check if this namespace was excluded.
|
| - * Note that at this point only the exclusions defined
|
| - * on the topmost stylesheet element are in the exclusion-list.
|
| - */
|
| - for (i = 0;i < style->exclPrefixNr;i++) {
|
| - if (xmlStrEqual(cur->href, style->exclPrefixTab[i]))
|
| - goto skip_ns;
|
| - }
|
| - if (ret == NULL) {
|
| - ret =
|
| - (xmlNsPtr *) xmlMalloc((maxns + 1) *
|
| - sizeof(xmlNsPtr));
|
| - if (ret == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltGetInheritedNsList : out of memory!\n");
|
| - return(0);
|
| - }
|
| - ret[nbns] = NULL;
|
| - }
|
| - /*
|
| - * Skip shadowed namespace bindings.
|
| - */
|
| - for (i = 0; i < nbns; i++) {
|
| - if ((cur->prefix == ret[i]->prefix) ||
|
| - (xmlStrEqual(cur->prefix, ret[i]->prefix)))
|
| - break;
|
| - }
|
| - if (i >= nbns) {
|
| - if (nbns >= maxns) {
|
| - maxns *= 2;
|
| - ret = (xmlNsPtr *) xmlRealloc(ret,
|
| - (maxns +
|
| - 1) *
|
| - sizeof(xmlNsPtr));
|
| - if (ret == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltGetInheritedNsList : realloc failed!\n");
|
| - return(0);
|
| - }
|
| - }
|
| - ret[nbns++] = cur;
|
| - ret[nbns] = NULL;
|
| - }
|
| -skip_ns:
|
| - cur = cur->next;
|
| - }
|
| - }
|
| - node = node->parent;
|
| - }
|
| - if (nbns != 0) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "template has %d inherited namespaces\n", nbns);
|
| -#endif
|
| - template->inheritedNsNr = nbns;
|
| - template->inheritedNs = ret;
|
| - }
|
| - return (nbns);
|
| -}
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetOutput:
|
| - * @style: the XSLT stylesheet
|
| - * @cur: the "output" element
|
| - *
|
| - * parse an XSLT stylesheet output element and record
|
| - * information related to the stylesheet output
|
| - */
|
| -
|
| -void
|
| -xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur)
|
| -{
|
| - xmlChar *elements,
|
| - *prop;
|
| - xmlChar *element,
|
| - *end;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL);
|
| - if (prop != NULL) {
|
| - if (style->version != NULL)
|
| - xmlFree(style->version);
|
| - style->version = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL);
|
| - if (prop != NULL) {
|
| - if (style->encoding != NULL)
|
| - xmlFree(style->encoding);
|
| - style->encoding = prop;
|
| - }
|
| -
|
| - /* relaxed to support xt:document
|
| - * TODO KB: What does "relaxed to support xt:document" mean?
|
| - */
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *URI;
|
| -
|
| - if (style->method != NULL)
|
| - xmlFree(style->method);
|
| - style->method = NULL;
|
| - if (style->methodURI != NULL)
|
| - xmlFree(style->methodURI);
|
| - style->methodURI = NULL;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(cur, &prop);
|
| - if (prop == NULL) {
|
| - if (style != NULL) style->errors++;
|
| - } else if (URI == NULL) {
|
| - if ((xmlStrEqual(prop, (const xmlChar *) "xml")) ||
|
| - (xmlStrEqual(prop, (const xmlChar *) "html")) ||
|
| - (xmlStrEqual(prop, (const xmlChar *) "text"))) {
|
| - style->method = prop;
|
| - } else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "invalid value for method: %s\n", prop);
|
| - if (style != NULL) style->warnings++;
|
| - }
|
| - } else {
|
| - style->method = prop;
|
| - style->methodURI = xmlStrdup(URI);
|
| - }
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL);
|
| - if (prop != NULL) {
|
| - if (style->doctypeSystem != NULL)
|
| - xmlFree(style->doctypeSystem);
|
| - style->doctypeSystem = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL);
|
| - if (prop != NULL) {
|
| - if (style->doctypePublic != NULL)
|
| - xmlFree(style->doctypePublic);
|
| - style->doctypePublic = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL);
|
| - if (prop != NULL) {
|
| - if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
|
| - style->standalone = 1;
|
| - } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
|
| - style->standalone = 0;
|
| - } else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "invalid value for standalone: %s\n", prop);
|
| - style->errors++;
|
| - }
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL);
|
| - if (prop != NULL) {
|
| - if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
|
| - style->indent = 1;
|
| - } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
|
| - style->indent = 0;
|
| - } else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "invalid value for indent: %s\n", prop);
|
| - style->errors++;
|
| - }
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL);
|
| - if (prop != NULL) {
|
| - if (xmlStrEqual(prop, (const xmlChar *) "yes")) {
|
| - style->omitXmlDeclaration = 1;
|
| - } else if (xmlStrEqual(prop, (const xmlChar *) "no")) {
|
| - style->omitXmlDeclaration = 0;
|
| - } else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "invalid value for omit-xml-declaration: %s\n",
|
| - prop);
|
| - style->errors++;
|
| - }
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements",
|
| - NULL);
|
| - if (elements != NULL) {
|
| - if (style->cdataSection == NULL)
|
| - style->cdataSection = xmlHashCreate(10);
|
| - if (style->cdataSection == NULL)
|
| - return;
|
| -
|
| - element = elements;
|
| - while (*element != 0) {
|
| - while (IS_BLANK(*element))
|
| - element++;
|
| - if (*element == 0)
|
| - break;
|
| - end = element;
|
| - while ((*end != 0) && (!IS_BLANK(*end)))
|
| - end++;
|
| - element = xmlStrndup(element, end - element);
|
| - if (element) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "add cdata section output element %s\n",
|
| - element);
|
| -#endif
|
| - if (xmlValidateQName(BAD_CAST element, 0) != 0) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Attribute 'cdata-section-elements': The value "
|
| - "'%s' is not a valid QName.\n", element);
|
| - xmlFree(element);
|
| - style->errors++;
|
| - } else {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(cur, &element);
|
| - if (element == NULL) {
|
| - /*
|
| - * TODO: We'll report additionally an error
|
| - * via the stylesheet's error handling.
|
| - */
|
| - xsltTransformError(NULL, style, cur,
|
| - "Attribute 'cdata-section-elements': The value "
|
| - "'%s' is not a valid QName.\n", element);
|
| - style->errors++;
|
| - } else {
|
| - xmlNsPtr ns;
|
| -
|
| - /*
|
| - * XSLT-1.0 "Each QName is expanded into an
|
| - * expanded-name using the namespace declarations in
|
| - * effect on the xsl:output element in which the QName
|
| - * occurs; if there is a default namespace, it is used
|
| - * for QNames that do not have a prefix"
|
| - * NOTE: Fix of bug #339570.
|
| - */
|
| - if (URI == NULL) {
|
| - ns = xmlSearchNs(style->doc, cur, NULL);
|
| - if (ns != NULL)
|
| - URI = ns->href;
|
| - }
|
| - xmlHashAddEntry2(style->cdataSection, element, URI,
|
| - (void *) "cdata");
|
| - xmlFree(element);
|
| - }
|
| - }
|
| - }
|
| - element = end;
|
| - }
|
| - xmlFree(elements);
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL);
|
| - if (prop != NULL) {
|
| - if (style->mediaType)
|
| - xmlFree(style->mediaType);
|
| - style->mediaType = prop;
|
| - }
|
| - if (cur->children != NULL) {
|
| - xsltParseContentError(style, cur->children);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltParseStylesheetDecimalFormat:
|
| - * @style: the XSLT stylesheet
|
| - * @cur: the "decimal-format" element
|
| - *
|
| - * <!-- Category: top-level-element -->
|
| - * <xsl:decimal-format
|
| - * name = qname, decimal-separator = char, grouping-separator = char,
|
| - * infinity = string, minus-sign = char, NaN = string, percent = char
|
| - * per-mille = char, zero-digit = char, digit = char,
|
| - * pattern-separator = char />
|
| - *
|
| - * parse an XSLT stylesheet decimal-format element and
|
| - * and record the formatting characteristics
|
| - */
|
| -static void
|
| -xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur)
|
| -{
|
| - xmlChar *prop;
|
| - xsltDecimalFormatPtr format;
|
| - xsltDecimalFormatPtr iter;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - format = style->decimalFormat;
|
| -
|
| - prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *nsUri;
|
| -
|
| - if (xmlValidateQName(prop, 0) != 0) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsl:decimal-format: Invalid QName '%s'.\n", prop);
|
| - style->warnings++;
|
| - xmlFree(prop);
|
| - return;
|
| - }
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - nsUri = xsltGetQNameURI(cur, &prop);
|
| - if (prop == NULL) {
|
| - style->warnings++;
|
| - return;
|
| - }
|
| - format = xsltDecimalFormatGetByQName(style, nsUri, prop);
|
| - if (format != NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylestyleDecimalFormat: %s already exists\n", prop);
|
| - style->warnings++;
|
| - xmlFree(prop);
|
| - return;
|
| - }
|
| - format = xsltNewDecimalFormat(nsUri, prop);
|
| - if (format == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n");
|
| - style->errors++;
|
| - xmlFree(prop);
|
| - return;
|
| - }
|
| - /* Append new decimal-format structure */
|
| - for (iter = style->decimalFormat; iter->next; iter = iter->next)
|
| - ;
|
| - if (iter)
|
| - iter->next = format;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL);
|
| - if (prop != NULL) {
|
| - if (format->decimalPoint != NULL) xmlFree(format->decimalPoint);
|
| - format->decimalPoint = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL);
|
| - if (prop != NULL) {
|
| - if (format->grouping != NULL) xmlFree(format->grouping);
|
| - format->grouping = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL);
|
| - if (prop != NULL) {
|
| - if (format->infinity != NULL) xmlFree(format->infinity);
|
| - format->infinity = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL);
|
| - if (prop != NULL) {
|
| - if (format->minusSign != NULL) xmlFree(format->minusSign);
|
| - format->minusSign = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL);
|
| - if (prop != NULL) {
|
| - if (format->noNumber != NULL) xmlFree(format->noNumber);
|
| - format->noNumber = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL);
|
| - if (prop != NULL) {
|
| - if (format->percent != NULL) xmlFree(format->percent);
|
| - format->percent = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL);
|
| - if (prop != NULL) {
|
| - if (format->permille != NULL) xmlFree(format->permille);
|
| - format->permille = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL);
|
| - if (prop != NULL) {
|
| - if (format->zeroDigit != NULL) xmlFree(format->zeroDigit);
|
| - format->zeroDigit = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL);
|
| - if (prop != NULL) {
|
| - if (format->digit != NULL) xmlFree(format->digit);
|
| - format->digit = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL);
|
| - if (prop != NULL) {
|
| - if (format->patternSeparator != NULL) xmlFree(format->patternSeparator);
|
| - format->patternSeparator = prop;
|
| - }
|
| - if (cur->children != NULL) {
|
| - xsltParseContentError(style, cur->children);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltParseStylesheetPreserveSpace:
|
| - * @style: the XSLT stylesheet
|
| - * @cur: the "preserve-space" element
|
| - *
|
| - * parse an XSLT stylesheet preserve-space element and record
|
| - * elements needing preserving
|
| - */
|
| -
|
| -static void
|
| -xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
|
| - xmlChar *elements;
|
| - xmlChar *element, *end;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
|
| - if (elements == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylesheetPreserveSpace: missing elements attribute\n");
|
| - if (style != NULL) style->warnings++;
|
| - return;
|
| - }
|
| -
|
| - if (style->stripSpaces == NULL)
|
| - style->stripSpaces = xmlHashCreate(10);
|
| - if (style->stripSpaces == NULL)
|
| - return;
|
| -
|
| - element = elements;
|
| - while (*element != 0) {
|
| - while (IS_BLANK(*element)) element++;
|
| - if (*element == 0)
|
| - break;
|
| - end = element;
|
| - while ((*end != 0) && (!IS_BLANK(*end))) end++;
|
| - element = xmlStrndup(element, end - element);
|
| - if (element) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "add preserved space element %s\n", element);
|
| -#endif
|
| - if (xmlStrEqual(element, (const xmlChar *)"*")) {
|
| - style->stripAll = -1;
|
| - } else {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(cur, &element);
|
| -
|
| - xmlHashAddEntry2(style->stripSpaces, element, URI,
|
| - (xmlChar *) "preserve");
|
| - }
|
| - xmlFree(element);
|
| - }
|
| - element = end;
|
| - }
|
| - xmlFree(elements);
|
| - if (cur->children != NULL) {
|
| - xsltParseContentError(style, cur->children);
|
| - }
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -#else
|
| -/**
|
| - * xsltParseStylesheetExtPrefix:
|
| - * @style: the XSLT stylesheet
|
| - * @template: the "extension-element-prefixes" prefix
|
| - *
|
| - * parse an XSLT stylesheet's "extension-element-prefix" attribute value
|
| - * and register the namespaces of extension instruction.
|
| - * SPEC "A namespace is designated as an extension namespace by using
|
| - * an extension-element-prefixes attribute on:
|
| - * 1) an xsl:stylesheet element
|
| - * 2) an xsl:extension-element-prefixes attribute on a
|
| - * literal result element
|
| - * 3) an extension instruction."
|
| - */
|
| -static void
|
| -xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur,
|
| - int isXsltElem) {
|
| - xmlChar *prefixes;
|
| - xmlChar *prefix, *end;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - if (isXsltElem) {
|
| - /* For xsl:stylesheet/xsl:transform. */
|
| - prefixes = xmlGetNsProp(cur,
|
| - (const xmlChar *)"extension-element-prefixes", NULL);
|
| - } else {
|
| - /* For literal result elements and extension instructions. */
|
| - prefixes = xmlGetNsProp(cur,
|
| - (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE);
|
| - }
|
| - if (prefixes == NULL) {
|
| - return;
|
| - }
|
| -
|
| - prefix = prefixes;
|
| - while (*prefix != 0) {
|
| - while (IS_BLANK(*prefix)) prefix++;
|
| - if (*prefix == 0)
|
| - break;
|
| - end = prefix;
|
| - while ((*end != 0) && (!IS_BLANK(*end))) end++;
|
| - prefix = xmlStrndup(prefix, end - prefix);
|
| - if (prefix) {
|
| - xmlNsPtr ns;
|
| -
|
| - if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
|
| - ns = xmlSearchNs(style->doc, cur, NULL);
|
| - else
|
| - ns = xmlSearchNs(style->doc, cur, prefix);
|
| - if (ns == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsl:extension-element-prefix : undefined namespace %s\n",
|
| - prefix);
|
| - if (style != NULL) style->warnings++;
|
| - } else {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "add extension prefix %s\n", prefix);
|
| -#endif
|
| - xsltRegisterExtPrefix(style, prefix, ns->href);
|
| - }
|
| - xmlFree(prefix);
|
| - }
|
| - prefix = end;
|
| - }
|
| - xmlFree(prefixes);
|
| -}
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetStripSpace:
|
| - * @style: the XSLT stylesheet
|
| - * @cur: the "strip-space" element
|
| - *
|
| - * parse an XSLT stylesheet's strip-space element and record
|
| - * the elements needing stripping
|
| - */
|
| -
|
| -static void
|
| -xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) {
|
| - xmlChar *elements;
|
| - xmlChar *element, *end;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL);
|
| - if (elements == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylesheetStripSpace: missing elements attribute\n");
|
| - if (style != NULL) style->warnings++;
|
| - return;
|
| - }
|
| -
|
| - if (style->stripSpaces == NULL)
|
| - style->stripSpaces = xmlHashCreate(10);
|
| - if (style->stripSpaces == NULL)
|
| - return;
|
| -
|
| - element = elements;
|
| - while (*element != 0) {
|
| - while (IS_BLANK(*element)) element++;
|
| - if (*element == 0)
|
| - break;
|
| - end = element;
|
| - while ((*end != 0) && (!IS_BLANK(*end))) end++;
|
| - element = xmlStrndup(element, end - element);
|
| - if (element) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "add stripped space element %s\n", element);
|
| -#endif
|
| - if (xmlStrEqual(element, (const xmlChar *)"*")) {
|
| - style->stripAll = 1;
|
| - } else {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(cur, &element);
|
| -
|
| - xmlHashAddEntry2(style->stripSpaces, element, URI,
|
| - (xmlChar *) "strip");
|
| - }
|
| - xmlFree(element);
|
| - }
|
| - element = end;
|
| - }
|
| - xmlFree(elements);
|
| - if (cur->children != NULL) {
|
| - xsltParseContentError(style, cur->children);
|
| - }
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -#else
|
| -/**
|
| - * xsltParseStylesheetExcludePrefix:
|
| - * @style: the XSLT stylesheet
|
| - * @cur: the current point in the stylesheet
|
| - *
|
| - * parse an XSLT stylesheet exclude prefix and record
|
| - * namespaces needing stripping
|
| - *
|
| - * Returns the number of Excluded prefixes added at that level
|
| - */
|
| -
|
| -static int
|
| -xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur,
|
| - int isXsltElem)
|
| -{
|
| - int nb = 0;
|
| - xmlChar *prefixes;
|
| - xmlChar *prefix, *end;
|
| -
|
| - if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
|
| - return(0);
|
| -
|
| - if (isXsltElem)
|
| - prefixes = xmlGetNsProp(cur,
|
| - (const xmlChar *)"exclude-result-prefixes", NULL);
|
| - else
|
| - prefixes = xmlGetNsProp(cur,
|
| - (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE);
|
| -
|
| - if (prefixes == NULL) {
|
| - return(0);
|
| - }
|
| -
|
| - prefix = prefixes;
|
| - while (*prefix != 0) {
|
| - while (IS_BLANK(*prefix)) prefix++;
|
| - if (*prefix == 0)
|
| - break;
|
| - end = prefix;
|
| - while ((*end != 0) && (!IS_BLANK(*end))) end++;
|
| - prefix = xmlStrndup(prefix, end - prefix);
|
| - if (prefix) {
|
| - xmlNsPtr ns;
|
| -
|
| - if (xmlStrEqual(prefix, (const xmlChar *)"#default"))
|
| - ns = xmlSearchNs(style->doc, cur, NULL);
|
| - else
|
| - ns = xmlSearchNs(style->doc, cur, prefix);
|
| - if (ns == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsl:exclude-result-prefixes : undefined namespace %s\n",
|
| - prefix);
|
| - if (style != NULL) style->warnings++;
|
| - } else {
|
| - if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "exclude result prefix %s\n", prefix);
|
| -#endif
|
| - nb++;
|
| - }
|
| - }
|
| - xmlFree(prefix);
|
| - }
|
| - prefix = end;
|
| - }
|
| - xmlFree(prefixes);
|
| - return(nb);
|
| -}
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -
|
| -/*
|
| -* xsltTreeEnsureXMLDecl:
|
| -* @doc: the doc
|
| -*
|
| -* BIG NOTE:
|
| -* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c".
|
| -* Ensures that there is an XML namespace declaration on the doc.
|
| -*
|
| -* Returns the XML ns-struct or NULL on API and internal errors.
|
| -*/
|
| -static xmlNsPtr
|
| -xsltTreeEnsureXMLDecl(xmlDocPtr doc)
|
| -{
|
| - if (doc == NULL)
|
| - return (NULL);
|
| - if (doc->oldNs != NULL)
|
| - return (doc->oldNs);
|
| - {
|
| - xmlNsPtr ns;
|
| - ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
|
| - if (ns == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltTreeEnsureXMLDecl: Failed to allocate "
|
| - "the XML namespace.\n");
|
| - return (NULL);
|
| - }
|
| - memset(ns, 0, sizeof(xmlNs));
|
| - ns->type = XML_LOCAL_NAMESPACE;
|
| - /*
|
| - * URGENT TODO: revisit this.
|
| - */
|
| -#ifdef LIBXML_NAMESPACE_DICT
|
| - if (doc->dict)
|
| - ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1);
|
| - else
|
| - ns->href = xmlStrdup(XML_XML_NAMESPACE);
|
| -#else
|
| - ns->href = xmlStrdup(XML_XML_NAMESPACE);
|
| -#endif
|
| - ns->prefix = xmlStrdup((const xmlChar *)"xml");
|
| - doc->oldNs = ns;
|
| - return (ns);
|
| - }
|
| -}
|
| -
|
| -/*
|
| -* xsltTreeAcquireStoredNs:
|
| -* @doc: the doc
|
| -* @nsName: the namespace name
|
| -* @prefix: the prefix
|
| -*
|
| -* BIG NOTE:
|
| -* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c".
|
| -* Creates or reuses an xmlNs struct on doc->oldNs with
|
| -* the given prefix and namespace name.
|
| -*
|
| -* Returns the aquired ns struct or NULL in case of an API
|
| -* or internal error.
|
| -*/
|
| -static xmlNsPtr
|
| -xsltTreeAcquireStoredNs(xmlDocPtr doc,
|
| - const xmlChar *nsName,
|
| - const xmlChar *prefix)
|
| -{
|
| - xmlNsPtr ns;
|
| -
|
| - if (doc == NULL)
|
| - return (NULL);
|
| - if (doc->oldNs != NULL)
|
| - ns = doc->oldNs;
|
| - else
|
| - ns = xsltTreeEnsureXMLDecl(doc);
|
| - if (ns == NULL)
|
| - return (NULL);
|
| - if (ns->next != NULL) {
|
| - /* Reuse. */
|
| - ns = ns->next;
|
| - while (ns != NULL) {
|
| - if ((ns->prefix == NULL) != (prefix == NULL)) {
|
| - /* NOP */
|
| - } else if (prefix == NULL) {
|
| - if (xmlStrEqual(ns->href, nsName))
|
| - return (ns);
|
| - } else {
|
| - if ((ns->prefix[0] == prefix[0]) &&
|
| - xmlStrEqual(ns->prefix, prefix) &&
|
| - xmlStrEqual(ns->href, nsName))
|
| - return (ns);
|
| -
|
| - }
|
| - if (ns->next == NULL)
|
| - break;
|
| - ns = ns->next;
|
| - }
|
| - }
|
| - /* Create. */
|
| - ns->next = xmlNewNs(NULL, nsName, prefix);
|
| - return (ns->next);
|
| -}
|
| -
|
| -/**
|
| - * xsltLREBuildEffectiveNs:
|
| - *
|
| - * Apply ns-aliasing on the namespace of the given @elem and
|
| - * its attributes.
|
| - */
|
| -static int
|
| -xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr elem)
|
| -{
|
| - xmlNsPtr ns;
|
| - xsltNsAliasPtr alias;
|
| -
|
| - if ((cctxt == NULL) || (elem == NULL))
|
| - return(-1);
|
| - if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases))
|
| - return(0);
|
| -
|
| - alias = cctxt->nsAliases;
|
| - while (alias != NULL) {
|
| - if ( /* If both namespaces are NULL... */
|
| - ( (elem->ns == NULL) &&
|
| - ((alias->literalNs == NULL) ||
|
| - (alias->literalNs->href == NULL)) ) ||
|
| - /* ... or both namespace are equal */
|
| - ( (elem->ns != NULL) &&
|
| - (alias->literalNs != NULL) &&
|
| - xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
|
| - {
|
| - if ((alias->targetNs != NULL) &&
|
| - (alias->targetNs->href != NULL))
|
| - {
|
| - /*
|
| - * Convert namespace.
|
| - */
|
| - if (elem->doc == alias->docOfTargetNs) {
|
| - /*
|
| - * This is the nice case: same docs.
|
| - * This will eventually assign a ns-decl which
|
| - * is shadowed, but this has no negative effect on
|
| - * the generation of the result tree.
|
| - */
|
| - elem->ns = alias->targetNs;
|
| - } else {
|
| - /*
|
| - * This target xmlNs originates from a different
|
| - * stylesheet tree. Try to locate it in the
|
| - * in-scope namespaces.
|
| - * OPTIMIZE TODO: Use the compiler-node-info inScopeNs.
|
| - */
|
| - ns = xmlSearchNs(elem->doc, elem,
|
| - alias->targetNs->prefix);
|
| - /*
|
| - * If no matching ns-decl found, then assign a
|
| - * ns-decl stored in xmlDoc.
|
| - */
|
| - if ((ns == NULL) ||
|
| - (! xmlStrEqual(ns->href, alias->targetNs->href)))
|
| - {
|
| - /*
|
| - * BIG NOTE: The use of xsltTreeAcquireStoredNs()
|
| - * is not very efficient, but currently I don't
|
| - * see an other way of *safely* changing a node's
|
| - * namespace, since the xmlNs struct in
|
| - * alias->targetNs might come from an other
|
| - * stylesheet tree. So we need to anchor it in the
|
| - * current document, without adding it to the tree,
|
| - * which would otherwise change the in-scope-ns
|
| - * semantic of the tree.
|
| - */
|
| - ns = xsltTreeAcquireStoredNs(elem->doc,
|
| - alias->targetNs->href,
|
| - alias->targetNs->prefix);
|
| -
|
| - if (ns == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Internal error in "
|
| - "xsltLREBuildEffectiveNs(): "
|
| - "failed to acquire a stored "
|
| - "ns-declaration.\n");
|
| - cctxt->style->errors++;
|
| - return(-1);
|
| -
|
| - }
|
| - }
|
| - elem->ns = ns;
|
| - }
|
| - } else {
|
| - /*
|
| - * Move into or leave in the NULL namespace.
|
| - */
|
| - elem->ns = NULL;
|
| - }
|
| - break;
|
| - }
|
| - alias = alias->next;
|
| - }
|
| - /*
|
| - * Same with attributes of literal result elements.
|
| - */
|
| - if (elem->properties != NULL) {
|
| - xmlAttrPtr attr = elem->properties;
|
| -
|
| - while (attr != NULL) {
|
| - if (attr->ns == NULL) {
|
| - attr = attr->next;
|
| - continue;
|
| - }
|
| - alias = cctxt->nsAliases;
|
| - while (alias != NULL) {
|
| - if ( /* If both namespaces are NULL... */
|
| - ( (elem->ns == NULL) &&
|
| - ((alias->literalNs == NULL) ||
|
| - (alias->literalNs->href == NULL)) ) ||
|
| - /* ... or both namespace are equal */
|
| - ( (elem->ns != NULL) &&
|
| - (alias->literalNs != NULL) &&
|
| - xmlStrEqual(elem->ns->href, alias->literalNs->href) ) )
|
| - {
|
| - if ((alias->targetNs != NULL) &&
|
| - (alias->targetNs->href != NULL))
|
| - {
|
| - if (elem->doc == alias->docOfTargetNs) {
|
| - elem->ns = alias->targetNs;
|
| - } else {
|
| - ns = xmlSearchNs(elem->doc, elem,
|
| - alias->targetNs->prefix);
|
| - if ((ns == NULL) ||
|
| - (! xmlStrEqual(ns->href, alias->targetNs->href)))
|
| - {
|
| - ns = xsltTreeAcquireStoredNs(elem->doc,
|
| - alias->targetNs->href,
|
| - alias->targetNs->prefix);
|
| -
|
| - if (ns == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Internal error in "
|
| - "xsltLREBuildEffectiveNs(): "
|
| - "failed to acquire a stored "
|
| - "ns-declaration.\n");
|
| - cctxt->style->errors++;
|
| - return(-1);
|
| -
|
| - }
|
| - }
|
| - elem->ns = ns;
|
| - }
|
| - } else {
|
| - /*
|
| - * Move into or leave in the NULL namespace.
|
| - */
|
| - elem->ns = NULL;
|
| - }
|
| - break;
|
| - }
|
| - alias = alias->next;
|
| - }
|
| -
|
| - attr = attr->next;
|
| - }
|
| - }
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltLREBuildEffectiveNsNodes:
|
| - *
|
| - * Computes the effective namespaces nodes for a literal result
|
| - * element.
|
| - * @effectiveNs is the set of effective ns-nodes
|
| - * on the literal result element, which will be added to the result
|
| - * element if not already existing in the result tree.
|
| - * This means that excluded namespaces (via exclude-result-prefixes,
|
| - * extension-element-prefixes and the XSLT namespace) not added
|
| - * to the set.
|
| - * Namespace-aliasing was applied on the @effectiveNs.
|
| - */
|
| -static int
|
| -xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
|
| - xsltStyleItemLRElementInfoPtr item,
|
| - xmlNodePtr elem,
|
| - int isLRE)
|
| -{
|
| - xmlNsPtr ns, tmpns;
|
| - xsltEffectiveNsPtr effNs, lastEffNs = NULL;
|
| - int i, j, holdByElem;
|
| - xsltPointerListPtr extElemNs = cctxt->inode->extElemNs;
|
| - xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs;
|
| -
|
| - if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) ||
|
| - (item == NULL) || (item->effectiveNs != NULL))
|
| - return(-1);
|
| -
|
| - if (item->inScopeNs == NULL)
|
| - return(0);
|
| -
|
| - extElemNs = cctxt->inode->extElemNs;
|
| - exclResultNs = cctxt->inode->exclResultNs;
|
| -
|
| - for (i = 0; i < item->inScopeNs->totalNumber; i++) {
|
| - ns = item->inScopeNs->list[i];
|
| - /*
|
| - * Skip namespaces designated as excluded namespaces
|
| - * -------------------------------------------------
|
| - *
|
| - * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces
|
| - * which are target namespaces of namespace-aliases
|
| - * regardless if designated as excluded.
|
| - *
|
| - * Exclude the XSLT namespace.
|
| - */
|
| - if (xmlStrEqual(ns->href, XSLT_NAMESPACE))
|
| - goto skip_ns;
|
| -
|
| - /*
|
| - * Apply namespace aliasing
|
| - * ------------------------
|
| - *
|
| - * SPEC XSLT 2.0
|
| - * "- A namespace node whose string value is a literal namespace
|
| - * URI is not copied to the result tree.
|
| - * - A namespace node whose string value is a target namespace URI
|
| - * is copied to the result tree, whether or not the URI
|
| - * identifies an excluded namespace."
|
| - *
|
| - * NOTE: The ns-aliasing machanism is non-cascading.
|
| - * (checked with Saxon, Xalan and MSXML .NET).
|
| - * URGENT TODO: is style->nsAliases the effective list of
|
| - * ns-aliases, or do we need to lookup the whole
|
| - * import-tree?
|
| - * TODO: Get rid of import-tree lookup.
|
| - */
|
| - if (cctxt->hasNsAliases) {
|
| - xsltNsAliasPtr alias;
|
| - /*
|
| - * First check for being a target namespace.
|
| - */
|
| - alias = cctxt->nsAliases;
|
| - do {
|
| - /*
|
| - * TODO: Is xmlns="" handled already?
|
| - */
|
| - if ((alias->targetNs != NULL) &&
|
| - (xmlStrEqual(alias->targetNs->href, ns->href)))
|
| - {
|
| - /*
|
| - * Recognized as a target namespace; use it regardless
|
| - * if excluded otherwise.
|
| - */
|
| - goto add_effective_ns;
|
| - }
|
| - alias = alias->next;
|
| - } while (alias != NULL);
|
| -
|
| - alias = cctxt->nsAliases;
|
| - do {
|
| - /*
|
| - * TODO: Is xmlns="" handled already?
|
| - */
|
| - if ((alias->literalNs != NULL) &&
|
| - (xmlStrEqual(alias->literalNs->href, ns->href)))
|
| - {
|
| - /*
|
| - * Recognized as an namespace alias; do not use it.
|
| - */
|
| - goto skip_ns;
|
| - }
|
| - alias = alias->next;
|
| - } while (alias != NULL);
|
| - }
|
| -
|
| - /*
|
| - * Exclude excluded result namespaces.
|
| - */
|
| - if (exclResultNs) {
|
| - for (j = 0; j < exclResultNs->number; j++)
|
| - if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j]))
|
| - goto skip_ns;
|
| - }
|
| - /*
|
| - * Exclude extension-element namespaces.
|
| - */
|
| - if (extElemNs) {
|
| - for (j = 0; j < extElemNs->number; j++)
|
| - if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
|
| - goto skip_ns;
|
| - }
|
| -
|
| -add_effective_ns:
|
| - /*
|
| - * OPTIMIZE TODO: This information may not be needed.
|
| - */
|
| - if (isLRE && (elem->nsDef != NULL)) {
|
| - holdByElem = 0;
|
| - tmpns = elem->nsDef;
|
| - do {
|
| - if (tmpns == ns) {
|
| - holdByElem = 1;
|
| - break;
|
| - }
|
| - tmpns = tmpns->next;
|
| - } while (tmpns != NULL);
|
| - } else
|
| - holdByElem = 0;
|
| -
|
| -
|
| - /*
|
| - * Add the effective namespace declaration.
|
| - */
|
| - effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs));
|
| - if (effNs == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Internal error in xsltLREBuildEffectiveNs(): "
|
| - "failed to allocate memory.\n");
|
| - cctxt->style->errors++;
|
| - return(-1);
|
| - }
|
| - if (cctxt->psData->effectiveNs == NULL) {
|
| - cctxt->psData->effectiveNs = effNs;
|
| - effNs->nextInStore = NULL;
|
| - } else {
|
| - effNs->nextInStore = cctxt->psData->effectiveNs;
|
| - cctxt->psData->effectiveNs = effNs;
|
| - }
|
| -
|
| - effNs->next = NULL;
|
| - effNs->prefix = ns->prefix;
|
| - effNs->nsName = ns->href;
|
| - effNs->holdByElem = holdByElem;
|
| -
|
| - if (lastEffNs == NULL)
|
| - item->effectiveNs = effNs;
|
| - else
|
| - lastEffNs->next = effNs;
|
| - lastEffNs = effNs;
|
| -
|
| -skip_ns:
|
| - {}
|
| - }
|
| - return(0);
|
| -}
|
| -
|
| -
|
| -/**
|
| - * xsltLREInfoCreate:
|
| - *
|
| - * @isLRE: indicates if the given @elem is a literal result element
|
| - *
|
| - * Creates a new info for a literal result element.
|
| - */
|
| -static int
|
| -xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr elem,
|
| - int isLRE)
|
| -{
|
| - xsltStyleItemLRElementInfoPtr item;
|
| -
|
| - if ((cctxt == NULL) || (cctxt->inode == NULL))
|
| - return(-1);
|
| -
|
| - item = (xsltStyleItemLRElementInfoPtr)
|
| - xmlMalloc(sizeof(xsltStyleItemLRElementInfo));
|
| - if (item == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "Internal error in xsltLREInfoCreate(): "
|
| - "memory allocation failed.\n");
|
| - cctxt->style->errors++;
|
| - return(-1);
|
| - }
|
| - memset(item, 0, sizeof(xsltStyleItemLRElementInfo));
|
| - item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT;
|
| - /*
|
| - * Store it in the stylesheet.
|
| - */
|
| - item->next = cctxt->style->preComps;
|
| - cctxt->style->preComps = (xsltElemPreCompPtr) item;
|
| - /*
|
| - * @inScopeNs are used for execution of XPath expressions
|
| - * in AVTs.
|
| - */
|
| - item->inScopeNs = cctxt->inode->inScopeNs;
|
| -
|
| - if (elem)
|
| - xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE);
|
| -
|
| - cctxt->inode->litResElemInfo = item;
|
| - cctxt->inode->nsChanged = 0;
|
| - cctxt->maxLREs++;
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltCompilerVarInfoPush:
|
| - * @cctxt: the compilation context
|
| - *
|
| - * Pushes a new var/param info onto the stack.
|
| - *
|
| - * Returns the acquired variable info.
|
| - */
|
| -static xsltVarInfoPtr
|
| -xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr inst,
|
| - const xmlChar *name,
|
| - const xmlChar *nsName)
|
| -{
|
| - xsltVarInfoPtr ivar;
|
| -
|
| - if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) {
|
| - ivar = cctxt->ivar->next;
|
| - } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) {
|
| - ivar = cctxt->ivars;
|
| - } else {
|
| - ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo));
|
| - if (ivar == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, inst,
|
| - "xsltParseInScopeVarPush: xmlMalloc() failed!\n");
|
| - cctxt->style->errors++;
|
| - return(NULL);
|
| - }
|
| - /* memset(retVar, 0, sizeof(xsltInScopeVar)); */
|
| - if (cctxt->ivars == NULL) {
|
| - cctxt->ivars = ivar;
|
| - ivar->prev = NULL;
|
| - } else {
|
| - cctxt->ivar->next = ivar;
|
| - ivar->prev = cctxt->ivar;
|
| - }
|
| - cctxt->ivar = ivar;
|
| - ivar->next = NULL;
|
| - }
|
| - ivar->depth = cctxt->depth;
|
| - ivar->name = name;
|
| - ivar->nsName = nsName;
|
| - return(ivar);
|
| -}
|
| -
|
| -/**
|
| - * xsltCompilerVarInfoPop:
|
| - * @cctxt: the compilation context
|
| - *
|
| - * Pops all var/param infos from the stack, which
|
| - * have the current depth.
|
| - */
|
| -static void
|
| -xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt)
|
| -{
|
| -
|
| - while ((cctxt->ivar != NULL) &&
|
| - (cctxt->ivar->depth > cctxt->depth))
|
| - {
|
| - cctxt->ivar = cctxt->ivar->prev;
|
| - }
|
| -}
|
| -
|
| -/*
|
| -* xsltCompilerNodePush:
|
| -*
|
| -* @cctxt: the compilation context
|
| -* @node: the node to be pushed (this can also be the doc-node)
|
| -*
|
| -*
|
| -*
|
| -* Returns the current node info structure or
|
| -* NULL in case of an internal error.
|
| -*/
|
| -static xsltCompilerNodeInfoPtr
|
| -xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| - xsltCompilerNodeInfoPtr inode, iprev;
|
| -
|
| - if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) {
|
| - inode = cctxt->inode->next;
|
| - } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) {
|
| - inode = cctxt->inodeList;
|
| - } else {
|
| - /*
|
| - * Create a new node-info.
|
| - */
|
| - inode = (xsltCompilerNodeInfoPtr)
|
| - xmlMalloc(sizeof(xsltCompilerNodeInfo));
|
| - if (inode == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "xsltCompilerNodePush: malloc failed.\n");
|
| - return(NULL);
|
| - }
|
| - memset(inode, 0, sizeof(xsltCompilerNodeInfo));
|
| - if (cctxt->inodeList == NULL)
|
| - cctxt->inodeList = inode;
|
| - else {
|
| - cctxt->inodeLast->next = inode;
|
| - inode->prev = cctxt->inodeLast;
|
| - }
|
| - cctxt->inodeLast = inode;
|
| - cctxt->maxNodeInfos++;
|
| - if (cctxt->inode == NULL) {
|
| - cctxt->inode = inode;
|
| - /*
|
| - * Create an initial literal result element info for
|
| - * the root of the stylesheet.
|
| - */
|
| - xsltLREInfoCreate(cctxt, NULL, 0);
|
| - }
|
| - }
|
| - cctxt->depth++;
|
| - cctxt->inode = inode;
|
| - /*
|
| - * REVISIT TODO: Keep the reset always complete.
|
| - * NOTE: Be carefull with the @node, since it might be
|
| - * a doc-node.
|
| - */
|
| - inode->node = node;
|
| - inode->depth = cctxt->depth;
|
| - inode->templ = NULL;
|
| - inode->category = XSLT_ELEMENT_CATEGORY_XSLT;
|
| - inode->type = 0;
|
| - inode->item = NULL;
|
| - inode->curChildType = 0;
|
| - inode->extContentHandled = 0;
|
| - inode->isRoot = 0;
|
| -
|
| - if (inode->prev != NULL) {
|
| - iprev = inode->prev;
|
| - /*
|
| - * Inherit the following information:
|
| - * ---------------------------------
|
| - *
|
| - * In-scope namespaces
|
| - */
|
| - inode->inScopeNs = iprev->inScopeNs;
|
| - /*
|
| - * Info for literal result elements
|
| - */
|
| - inode->litResElemInfo = iprev->litResElemInfo;
|
| - inode->nsChanged = iprev->nsChanged;
|
| - /*
|
| - * Excluded result namespaces
|
| - */
|
| - inode->exclResultNs = iprev->exclResultNs;
|
| - /*
|
| - * Extension instruction namespaces
|
| - */
|
| - inode->extElemNs = iprev->extElemNs;
|
| - /*
|
| - * Whitespace preservation
|
| - */
|
| - inode->preserveWhitespace = iprev->preserveWhitespace;
|
| - /*
|
| - * Forwards-compatible mode
|
| - */
|
| - inode->forwardsCompat = iprev->forwardsCompat;
|
| - } else {
|
| - inode->inScopeNs = NULL;
|
| - inode->exclResultNs = NULL;
|
| - inode->extElemNs = NULL;
|
| - inode->preserveWhitespace = 0;
|
| - inode->forwardsCompat = 0;
|
| - }
|
| -
|
| - return(inode);
|
| -}
|
| -
|
| -/*
|
| -* xsltCompilerNodePop:
|
| -*
|
| -* @cctxt: the compilation context
|
| -* @node: the node to be pushed (this can also be the doc-node)
|
| -*
|
| -* Pops the current node info.
|
| -*/
|
| -static void
|
| -xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| - if (cctxt->inode == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltCompilerNodePop: Top-node mismatch.\n");
|
| - return;
|
| - }
|
| - /*
|
| - * NOTE: Be carefull with the @node, since it might be
|
| - * a doc-node.
|
| - */
|
| - if (cctxt->inode->node != node) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltCompilerNodePop: Node mismatch.\n");
|
| - goto mismatch;
|
| - }
|
| - if (cctxt->inode->depth != cctxt->depth) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltCompilerNodePop: Depth mismatch.\n");
|
| - goto mismatch;
|
| - }
|
| - cctxt->depth--;
|
| - /*
|
| - * Pop information of variables.
|
| - */
|
| - if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
|
| - xsltCompilerVarInfoPop(cctxt);
|
| -
|
| - cctxt->inode = cctxt->inode->prev;
|
| - if (cctxt->inode != NULL)
|
| - cctxt->inode->curChildType = 0;
|
| - return;
|
| -
|
| -mismatch:
|
| - {
|
| - const xmlChar *nsName = NULL, *name = NULL;
|
| - const xmlChar *infnsName = NULL, *infname = NULL;
|
| -
|
| - if (node) {
|
| - if (node->type == XML_ELEMENT_NODE) {
|
| - name = node->name;
|
| - if (node->ns != NULL)
|
| - nsName = node->ns->href;
|
| - else
|
| - nsName = BAD_CAST "";
|
| - } else {
|
| - name = BAD_CAST "#document";
|
| - nsName = BAD_CAST "";
|
| - }
|
| - } else
|
| - name = BAD_CAST "Not given";
|
| -
|
| - if (cctxt->inode->node) {
|
| - if (node->type == XML_ELEMENT_NODE) {
|
| - infname = cctxt->inode->node->name;
|
| - if (cctxt->inode->node->ns != NULL)
|
| - infnsName = cctxt->inode->node->ns->href;
|
| - else
|
| - infnsName = BAD_CAST "";
|
| - } else {
|
| - infname = BAD_CAST "#document";
|
| - infnsName = BAD_CAST "";
|
| - }
|
| - } else
|
| - infname = BAD_CAST "Not given";
|
| -
|
| -
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltCompilerNodePop: Given : '%s' URI '%s'\n",
|
| - name, nsName);
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltCompilerNodePop: Expected: '%s' URI '%s'\n",
|
| - infname, infnsName);
|
| - }
|
| -}
|
| -
|
| -/*
|
| -* xsltCompilerBuildInScopeNsList:
|
| -*
|
| -* Create and store the list of in-scope namespaces for the given
|
| -* node in the stylesheet. If there are no changes in the in-scope
|
| -* namespaces then the last ns-info of the ancestor axis will be returned.
|
| -* Compilation-time only.
|
| -*
|
| -* Returns the ns-info or NULL if there are no namespaces in scope.
|
| -*/
|
| -static xsltNsListContainerPtr
|
| -xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| - xsltNsListContainerPtr nsi = NULL;
|
| - xmlNsPtr *list = NULL, ns;
|
| - int i, maxns = 5;
|
| - /*
|
| - * Create a new ns-list for this position in the node-tree.
|
| - * xmlGetNsList() will return NULL, if there are no ns-decls in the
|
| - * tree. Note that the ns-decl for the XML namespace is not added
|
| - * to the resulting list; the XPath module handles the XML namespace
|
| - * internally.
|
| - */
|
| - while (node != NULL) {
|
| - if (node->type == XML_ELEMENT_NODE) {
|
| - ns = node->nsDef;
|
| - while (ns != NULL) {
|
| - if (nsi == NULL) {
|
| - nsi = (xsltNsListContainerPtr)
|
| - xmlMalloc(sizeof(xsltNsListContainer));
|
| - if (nsi == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "xsltCompilerBuildInScopeNsList: "
|
| - "malloc failed!\n");
|
| - goto internal_err;
|
| - }
|
| - memset(nsi, 0, sizeof(xsltNsListContainer));
|
| - nsi->list =
|
| - (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr));
|
| - if (nsi->list == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "xsltCompilerBuildInScopeNsList: "
|
| - "malloc failed!\n");
|
| - goto internal_err;
|
| - }
|
| - nsi->list[0] = NULL;
|
| - }
|
| - /*
|
| - * Skip shadowed namespace bindings.
|
| - */
|
| - for (i = 0; i < nsi->totalNumber; i++) {
|
| - if ((ns->prefix == nsi->list[i]->prefix) ||
|
| - (xmlStrEqual(ns->prefix, nsi->list[i]->prefix)))
|
| - break;
|
| - }
|
| - if (i >= nsi->totalNumber) {
|
| - if (nsi->totalNumber +1 >= maxns) {
|
| - maxns *= 2;
|
| - nsi->list =
|
| - (xmlNsPtr *) xmlRealloc(nsi->list,
|
| - maxns * sizeof(xmlNsPtr));
|
| - if (nsi->list == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "xsltCompilerBuildInScopeNsList: "
|
| - "realloc failed!\n");
|
| - goto internal_err;
|
| - }
|
| - }
|
| - nsi->list[nsi->totalNumber++] = ns;
|
| - nsi->list[nsi->totalNumber] = NULL;
|
| - }
|
| -
|
| - ns = ns->next;
|
| - }
|
| - }
|
| - node = node->parent;
|
| - }
|
| - if (nsi == NULL)
|
| - return(NULL);
|
| - /*
|
| - * Move the default namespace to last position.
|
| - */
|
| - nsi->xpathNumber = nsi->totalNumber;
|
| - for (i = 0; i < nsi->totalNumber; i++) {
|
| - if (nsi->list[i]->prefix == NULL) {
|
| - ns = nsi->list[i];
|
| - nsi->list[i] = nsi->list[nsi->totalNumber-1];
|
| - nsi->list[nsi->totalNumber-1] = ns;
|
| - nsi->xpathNumber--;
|
| - break;
|
| - }
|
| - }
|
| - /*
|
| - * Store the ns-list in the stylesheet.
|
| - */
|
| - if (xsltPointerListAddSize(
|
| - (xsltPointerListPtr)cctxt->psData->inScopeNamespaces,
|
| - (void *) nsi, 5) == -1)
|
| - {
|
| - xmlFree(nsi);
|
| - nsi = NULL;
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n");
|
| - goto internal_err;
|
| - }
|
| - /*
|
| - * Notify of change in status wrt namespaces.
|
| - */
|
| - if (cctxt->inode != NULL)
|
| - cctxt->inode->nsChanged = 1;
|
| -
|
| - return(nsi);
|
| -
|
| -internal_err:
|
| - if (list != NULL)
|
| - xmlFree(list);
|
| - cctxt->style->errors++;
|
| - return(NULL);
|
| -}
|
| -
|
| -static int
|
| -xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt,
|
| - xsltPointerListPtr list,
|
| - xmlNodePtr node,
|
| - const xmlChar *value)
|
| -{
|
| - xmlChar *cur, *end;
|
| - xmlNsPtr ns;
|
| -
|
| - if ((cctxt == NULL) || (value == NULL) || (list == NULL))
|
| - return(-1);
|
| -
|
| - list->number = 0;
|
| -
|
| - cur = (xmlChar *) value;
|
| - while (*cur != 0) {
|
| - while (IS_BLANK(*cur)) cur++;
|
| - if (*cur == 0)
|
| - break;
|
| - end = cur;
|
| - while ((*end != 0) && (!IS_BLANK(*end))) end++;
|
| - cur = xmlStrndup(cur, end - cur);
|
| - if (cur == NULL) {
|
| - cur = end;
|
| - continue;
|
| - }
|
| - /*
|
| - * TODO: Export and use xmlSearchNsByPrefixStrict()
|
| - * in Libxml2, tree.c, since xmlSearchNs() is in most
|
| - * cases not efficient and in some cases not correct.
|
| - *
|
| - * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value.
|
| - */
|
| - if ((cur[0] == '#') &&
|
| - xmlStrEqual(cur, (const xmlChar *)"#default"))
|
| - ns = xmlSearchNs(cctxt->style->doc, node, NULL);
|
| - else
|
| - ns = xmlSearchNs(cctxt->style->doc, node, cur);
|
| -
|
| - if (ns == NULL) {
|
| - /*
|
| - * TODO: Better to report the attr-node, otherwise
|
| - * the user won't know which attribute was invalid.
|
| - */
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "No namespace binding in scope for prefix '%s'.\n", cur);
|
| - /*
|
| - * XSLT-1.0: "It is an error if there is no namespace
|
| - * bound to the prefix on the element bearing the
|
| - * exclude-result-prefixes or xsl:exclude-result-prefixes
|
| - * attribute."
|
| - */
|
| - cctxt->style->errors++;
|
| - } else {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "resolved prefix '%s'\n", cur);
|
| -#endif
|
| - /*
|
| - * Note that we put the namespace name into the dict.
|
| - */
|
| - if (xsltPointerListAddSize(list,
|
| - (void *) xmlDictLookup(cctxt->style->dict,
|
| - ns->href, -1), 5) == -1)
|
| - {
|
| - xmlFree(cur);
|
| - goto internal_err;
|
| - }
|
| - }
|
| - xmlFree(cur);
|
| -
|
| - cur = end;
|
| - }
|
| - return(0);
|
| -
|
| -internal_err:
|
| - cctxt->style->errors++;
|
| - return(-1);
|
| -}
|
| -
|
| -/**
|
| - * xsltCompilerUtilsCreateMergedList:
|
| - * @dest: the destination list (optional)
|
| - * @first: the first list
|
| - * @second: the second list (optional)
|
| - *
|
| - * Appends the content of @second to @first into @destination.
|
| - * If @destination is NULL a new list will be created.
|
| - *
|
| - * Returns the merged list of items or NULL if there's nothing to merge.
|
| - */
|
| -static xsltPointerListPtr
|
| -xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first,
|
| - xsltPointerListPtr second)
|
| -{
|
| - xsltPointerListPtr ret;
|
| - size_t num;
|
| -
|
| - if (first)
|
| - num = first->number;
|
| - else
|
| - num = 0;
|
| - if (second)
|
| - num += second->number;
|
| - if (num == 0)
|
| - return(NULL);
|
| - ret = xsltPointerListCreate(num);
|
| - if (ret == NULL)
|
| - return(NULL);
|
| - /*
|
| - * Copy contents.
|
| - */
|
| - if ((first != NULL) && (first->number != 0)) {
|
| - memcpy(ret->items, first->items,
|
| - first->number * sizeof(void *));
|
| - if ((second != NULL) && (second->number != 0))
|
| - memcpy(ret->items + first->number, second->items,
|
| - second->number * sizeof(void *));
|
| - } else if ((second != NULL) && (second->number != 0))
|
| - memcpy(ret->items, (void *) second->items,
|
| - second->number * sizeof(void *));
|
| - ret->number = num;
|
| - return(ret);
|
| -}
|
| -
|
| -/*
|
| -* xsltParseExclResultPrefixes:
|
| -*
|
| -* Create and store the list of in-scope namespaces for the given
|
| -* node in the stylesheet. If there are no changes in the in-scope
|
| -* namespaces then the last ns-info of the ancestor axis will be returned.
|
| -* Compilation-time only.
|
| -*
|
| -* Returns the ns-info or NULL if there are no namespaces in scope.
|
| -*/
|
| -static xsltPointerListPtr
|
| -xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
|
| - xsltPointerListPtr def,
|
| - int instrCategory)
|
| -{
|
| - xsltPointerListPtr list = NULL;
|
| - xmlChar *value;
|
| - xmlAttrPtr attr;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL))
|
| - return(NULL);
|
| -
|
| - if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
|
| - attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL);
|
| - else
|
| - attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes",
|
| - XSLT_NAMESPACE);
|
| - if (attr == NULL)
|
| - return(def);
|
| -
|
| - if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
|
| - /*
|
| - * Mark the XSLT attr.
|
| - */
|
| - attr->psvi = (void *) xsltXSLTAttrMarker;
|
| - }
|
| -
|
| - if ((attr->children != NULL) &&
|
| - (attr->children->content != NULL))
|
| - value = attr->children->content;
|
| - else {
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Attribute 'exclude-result-prefixes': Invalid value.\n");
|
| - cctxt->style->errors++;
|
| - return(def);
|
| - }
|
| -
|
| - if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
|
| - BAD_CAST value) != 0)
|
| - goto exit;
|
| - if (cctxt->tmpList->number == 0)
|
| - goto exit;
|
| - /*
|
| - * Merge the list with the inherited list.
|
| - */
|
| - list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
|
| - if (list == NULL)
|
| - goto exit;
|
| - /*
|
| - * Store the list in the stylesheet/compiler context.
|
| - */
|
| - if (xsltPointerListAddSize(
|
| - cctxt->psData->exclResultNamespaces, list, 5) == -1)
|
| - {
|
| - xsltPointerListFree(list);
|
| - list = NULL;
|
| - goto exit;
|
| - }
|
| - /*
|
| - * Notify of change in status wrt namespaces.
|
| - */
|
| - if (cctxt->inode != NULL)
|
| - cctxt->inode->nsChanged = 1;
|
| -
|
| -exit:
|
| - if (list != NULL)
|
| - return(list);
|
| - else
|
| - return(def);
|
| -}
|
| -
|
| -/*
|
| -* xsltParseExtElemPrefixes:
|
| -*
|
| -* Create and store the list of in-scope namespaces for the given
|
| -* node in the stylesheet. If there are no changes in the in-scope
|
| -* namespaces then the last ns-info of the ancestor axis will be returned.
|
| -* Compilation-time only.
|
| -*
|
| -* Returns the ns-info or NULL if there are no namespaces in scope.
|
| -*/
|
| -static xsltPointerListPtr
|
| -xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
|
| - xsltPointerListPtr def,
|
| - int instrCategory)
|
| -{
|
| - xsltPointerListPtr list = NULL;
|
| - xmlAttrPtr attr;
|
| - xmlChar *value;
|
| - int i;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL))
|
| - return(NULL);
|
| -
|
| - if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
|
| - attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL);
|
| - else
|
| - attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes",
|
| - XSLT_NAMESPACE);
|
| - if (attr == NULL)
|
| - return(def);
|
| -
|
| - if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
|
| - /*
|
| - * Mark the XSLT attr.
|
| - */
|
| - attr->psvi = (void *) xsltXSLTAttrMarker;
|
| - }
|
| -
|
| - if ((attr->children != NULL) &&
|
| - (attr->children->content != NULL))
|
| - value = attr->children->content;
|
| - else {
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Attribute 'extension-element-prefixes': Invalid value.\n");
|
| - cctxt->style->errors++;
|
| - return(def);
|
| - }
|
| -
|
| -
|
| - if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node,
|
| - BAD_CAST value) != 0)
|
| - goto exit;
|
| -
|
| - if (cctxt->tmpList->number == 0)
|
| - goto exit;
|
| - /*
|
| - * REVISIT: Register the extension namespaces.
|
| - */
|
| - for (i = 0; i < cctxt->tmpList->number; i++)
|
| - xsltRegisterExtPrefix(cctxt->style, NULL,
|
| - BAD_CAST cctxt->tmpList->items[i]);
|
| - /*
|
| - * Merge the list with the inherited list.
|
| - */
|
| - list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList);
|
| - if (list == NULL)
|
| - goto exit;
|
| - /*
|
| - * Store the list in the stylesheet.
|
| - */
|
| - if (xsltPointerListAddSize(
|
| - cctxt->psData->extElemNamespaces, list, 5) == -1)
|
| - {
|
| - xsltPointerListFree(list);
|
| - list = NULL;
|
| - goto exit;
|
| - }
|
| - /*
|
| - * Notify of change in status wrt namespaces.
|
| - */
|
| - if (cctxt->inode != NULL)
|
| - cctxt->inode->nsChanged = 1;
|
| -
|
| -exit:
|
| - if (list != NULL)
|
| - return(list);
|
| - else
|
| - return(def);
|
| -}
|
| -
|
| -/*
|
| -* xsltParseAttrXSLTVersion:
|
| -*
|
| -* @cctxt: the compilation context
|
| -* @node: the element-node
|
| -* @isXsltElem: whether this is an XSLT element
|
| -*
|
| -* Parses the attribute xsl:version.
|
| -*
|
| -* Returns 1 if there was such an attribute, 0 if not and
|
| -* -1 if an internal or API error occured.
|
| -*/
|
| -static int
|
| -xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node,
|
| - int instrCategory)
|
| -{
|
| - xmlChar *value;
|
| - xmlAttrPtr attr;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL))
|
| - return(-1);
|
| -
|
| - if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT)
|
| - attr = xmlHasNsProp(node, BAD_CAST "version", NULL);
|
| - else
|
| - attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE);
|
| -
|
| - if (attr == NULL)
|
| - return(0);
|
| -
|
| - attr->psvi = (void *) xsltXSLTAttrMarker;
|
| -
|
| - if ((attr->children != NULL) &&
|
| - (attr->children->content != NULL))
|
| - value = attr->children->content;
|
| - else {
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Attribute 'version': Invalid value.\n");
|
| - cctxt->style->errors++;
|
| - return(1);
|
| - }
|
| -
|
| - if (! xmlStrEqual(value, (const xmlChar *)"1.0")) {
|
| - cctxt->inode->forwardsCompat = 1;
|
| - /*
|
| - * TODO: To what extent do we support the
|
| - * forwards-compatible mode?
|
| - */
|
| - /*
|
| - * Report this only once per compilation episode.
|
| - */
|
| - if (! cctxt->hasForwardsCompat) {
|
| - cctxt->hasForwardsCompat = 1;
|
| - cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING;
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Warning: the attribute xsl:version specifies a value "
|
| - "different from '1.0'. Switching to forwards-compatible "
|
| - "mode. Only features of XSLT 1.0 are supported by this "
|
| - "processor.\n");
|
| - cctxt->style->warnings++;
|
| - cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR;
|
| - }
|
| - } else {
|
| - cctxt->inode->forwardsCompat = 0;
|
| - }
|
| -
|
| - if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) {
|
| - /*
|
| - * Set a marker on XSLT attributes.
|
| - */
|
| - attr->psvi = (void *) xsltXSLTAttrMarker;
|
| - }
|
| - return(1);
|
| -}
|
| -
|
| -static int
|
| -xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| - xmlNodePtr deleteNode, cur, txt, textNode = NULL;
|
| - xmlDocPtr doc;
|
| - xsltStylesheetPtr style;
|
| - int internalize = 0, findSpaceAttr;
|
| - int xsltStylesheetElemDepth;
|
| - xmlAttrPtr attr;
|
| - xmlChar *value;
|
| - const xmlChar *name, *nsNameXSLT = NULL;
|
| - int strictWhitespace, inXSLText = 0;
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - xsltNsMapPtr nsMapItem;
|
| -#endif
|
| -
|
| - if ((cctxt == NULL) || (cctxt->style == NULL) ||
|
| - (node == NULL) || (node->type != XML_ELEMENT_NODE))
|
| - return(-1);
|
| -
|
| - doc = node->doc;
|
| - if (doc == NULL)
|
| - goto internal_err;
|
| -
|
| - style = cctxt->style;
|
| - if ((style->dict != NULL) && (doc->dict == style->dict))
|
| - internalize = 1;
|
| - else
|
| - style->internalized = 0;
|
| -
|
| - /*
|
| - * Init value of xml:space. Since this might be an embedded
|
| - * stylesheet, this is needed to be performed on the element
|
| - * where the stylesheet is rooted at, taking xml:space of
|
| - * ancestors into account.
|
| - */
|
| - if (! cctxt->simplified)
|
| - xsltStylesheetElemDepth = cctxt->depth +1;
|
| - else
|
| - xsltStylesheetElemDepth = 0;
|
| -
|
| - if (xmlNodeGetSpacePreserve(node) != 1)
|
| - cctxt->inode->preserveWhitespace = 0;
|
| - else
|
| - cctxt->inode->preserveWhitespace = 1;
|
| -
|
| - /*
|
| - * Eval if we should keep the old incorrect behaviour.
|
| - */
|
| - strictWhitespace = (cctxt->strict != 0) ? 1 : 0;
|
| -
|
| - nsNameXSLT = xsltConstNamespaceNameXSLT;
|
| -
|
| - deleteNode = NULL;
|
| - cur = node;
|
| - while (cur != NULL) {
|
| - if (deleteNode != NULL) {
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_BLANKS
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParsePreprocessStylesheetTree: removing node\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - deleteNode = NULL;
|
| - }
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| -
|
| - /*
|
| - * Clear the PSVI field.
|
| - */
|
| - cur->psvi = NULL;
|
| -
|
| - xsltCompilerNodePush(cctxt, cur);
|
| -
|
| - inXSLText = 0;
|
| - textNode = NULL;
|
| - findSpaceAttr = 1;
|
| - cctxt->inode->stripWhitespace = 0;
|
| - /*
|
| - * TODO: I'd love to use a string pointer comparison here :-/
|
| - */
|
| - if (IS_XSLT_ELEM(cur)) {
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - if (cur->ns->href != nsNameXSLT) {
|
| - nsMapItem = xsltNewNamespaceMapItem(cctxt,
|
| - doc, cur->ns, cur);
|
| - if (nsMapItem == NULL)
|
| - goto internal_err;
|
| - cur->ns->href = nsNameXSLT;
|
| - }
|
| -#endif
|
| -
|
| - if (cur->name == NULL)
|
| - goto process_attributes;
|
| - /*
|
| - * Mark the XSLT element for later recognition.
|
| - * TODO: Using the marker is still too dangerous, since if
|
| - * the parsing mechanism leaves out an XSLT element, then
|
| - * this might hit the transformation-mechanism, which
|
| - * will break if it doesn't expect such a marker.
|
| - */
|
| - /* cur->psvi = (void *) xsltXSLTElemMarker; */
|
| -
|
| - /*
|
| - * XSLT 2.0: "Any whitespace text node whose parent is
|
| - * one of the following elements is removed from the "
|
| - * tree, regardless of any xml:space attributes:..."
|
| - * xsl:apply-imports,
|
| - * xsl:apply-templates,
|
| - * xsl:attribute-set,
|
| - * xsl:call-template,
|
| - * xsl:choose,
|
| - * xsl:stylesheet, xsl:transform.
|
| - * XSLT 2.0: xsl:analyze-string,
|
| - * xsl:character-map,
|
| - * xsl:next-match
|
| - *
|
| - * TODO: I'd love to use a string pointer comparison here :-/
|
| - */
|
| - name = cur->name;
|
| - switch (*name) {
|
| - case 't':
|
| - if ((name[0] == 't') && (name[1] == 'e') &&
|
| - (name[2] == 'x') && (name[3] == 't') &&
|
| - (name[4] == 0))
|
| - {
|
| - /*
|
| - * Process the xsl:text element.
|
| - * ----------------------------
|
| - * Mark it for later recognition.
|
| - */
|
| - cur->psvi = (void *) xsltXSLTTextMarker;
|
| - /*
|
| - * For stylesheets, the set of
|
| - * whitespace-preserving element names
|
| - * consists of just xsl:text.
|
| - */
|
| - findSpaceAttr = 0;
|
| - cctxt->inode->preserveWhitespace = 1;
|
| - inXSLText = 1;
|
| - }
|
| - break;
|
| - case 'c':
|
| - if (xmlStrEqual(name, BAD_CAST "choose") ||
|
| - xmlStrEqual(name, BAD_CAST "call-template"))
|
| - cctxt->inode->stripWhitespace = 1;
|
| - break;
|
| - case 'a':
|
| - if (xmlStrEqual(name, BAD_CAST "apply-templates") ||
|
| - xmlStrEqual(name, BAD_CAST "apply-imports") ||
|
| - xmlStrEqual(name, BAD_CAST "attribute-set"))
|
| -
|
| - cctxt->inode->stripWhitespace = 1;
|
| - break;
|
| - default:
|
| - if (xsltStylesheetElemDepth == cctxt->depth) {
|
| - /*
|
| - * This is a xsl:stylesheet/xsl:transform.
|
| - */
|
| - cctxt->inode->stripWhitespace = 1;
|
| - break;
|
| - }
|
| -
|
| - if ((cur->prev != NULL) &&
|
| - (cur->prev->type == XML_TEXT_NODE))
|
| - {
|
| - /*
|
| - * XSLT 2.0 : "Any whitespace text node whose
|
| - * following-sibling node is an xsl:param or
|
| - * xsl:sort element is removed from the tree,
|
| - * regardless of any xml:space attributes."
|
| - */
|
| - if (((*name == 'p') || (*name == 's')) &&
|
| - (xmlStrEqual(name, BAD_CAST "param") ||
|
| - xmlStrEqual(name, BAD_CAST "sort")))
|
| - {
|
| - do {
|
| - if (IS_BLANK_NODE(cur->prev)) {
|
| - txt = cur->prev;
|
| - xmlUnlinkNode(txt);
|
| - xmlFreeNode(txt);
|
| - } else {
|
| - /*
|
| - * This will result in a content
|
| - * error, when hitting the parsing
|
| - * functions.
|
| - */
|
| - break;
|
| - }
|
| - } while (cur->prev);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - }
|
| -
|
| -process_attributes:
|
| - /*
|
| - * Process attributes.
|
| - * ------------------
|
| - */
|
| - if (cur->properties != NULL) {
|
| - if (cur->children == NULL)
|
| - findSpaceAttr = 0;
|
| - attr = cur->properties;
|
| - do {
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - if ((attr->ns) && (attr->ns->href != nsNameXSLT) &&
|
| - xmlStrEqual(attr->ns->href, nsNameXSLT))
|
| - {
|
| - nsMapItem = xsltNewNamespaceMapItem(cctxt,
|
| - doc, attr->ns, cur);
|
| - if (nsMapItem == NULL)
|
| - goto internal_err;
|
| - attr->ns->href = nsNameXSLT;
|
| - }
|
| -#endif
|
| - if (internalize) {
|
| - /*
|
| - * Internalize the attribute's value; the goal is to
|
| - * speed up operations and minimize used space by
|
| - * compiled stylesheets.
|
| - */
|
| - txt = attr->children;
|
| - /*
|
| - * NOTE that this assumes only one
|
| - * text-node in the attribute's content.
|
| - */
|
| - if ((txt != NULL) && (txt->content != NULL) &&
|
| - (!xmlDictOwns(style->dict, txt->content)))
|
| - {
|
| - value = (xmlChar *) xmlDictLookup(style->dict,
|
| - txt->content, -1);
|
| - xmlNodeSetContent(txt, NULL);
|
| - txt->content = value;
|
| - }
|
| - }
|
| - /*
|
| - * Process xml:space attributes.
|
| - * ----------------------------
|
| - */
|
| - if ((findSpaceAttr != 0) &&
|
| - (attr->ns != NULL) &&
|
| - (attr->name != NULL) &&
|
| - (attr->name[0] == 's') &&
|
| - (attr->ns->prefix != NULL) &&
|
| - (attr->ns->prefix[0] == 'x') &&
|
| - (attr->ns->prefix[1] == 'm') &&
|
| - (attr->ns->prefix[2] == 'l') &&
|
| - (attr->ns->prefix[3] == 0))
|
| - {
|
| - value = xmlGetNsProp(cur, BAD_CAST "space",
|
| - XML_XML_NAMESPACE);
|
| - if (value != NULL) {
|
| - if (xmlStrEqual(value, BAD_CAST "preserve")) {
|
| - cctxt->inode->preserveWhitespace = 1;
|
| - } else if (xmlStrEqual(value, BAD_CAST "default")) {
|
| - cctxt->inode->preserveWhitespace = 0;
|
| - } else {
|
| - /* Invalid value for xml:space. */
|
| - xsltTransformError(NULL, style, cur,
|
| - "Attribute xml:space: Invalid value.\n");
|
| - cctxt->style->warnings++;
|
| - }
|
| - findSpaceAttr = 0;
|
| - xmlFree(value);
|
| - }
|
| -
|
| - }
|
| - attr = attr->next;
|
| - } while (attr != NULL);
|
| - }
|
| - /*
|
| - * We'll descend into the children of element nodes only.
|
| - */
|
| - if (cur->children != NULL) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - } else if ((cur->type == XML_TEXT_NODE) ||
|
| - (cur->type == XML_CDATA_SECTION_NODE))
|
| - {
|
| - /*
|
| - * Merge adjacent text/CDATA-section-nodes
|
| - * ---------------------------------------
|
| - * In order to avoid breaking of existing stylesheets,
|
| - * if the old behaviour is wanted (strictWhitespace == 0),
|
| - * then we *won't* merge adjacent text-nodes
|
| - * (except in xsl:text); this will ensure that whitespace-only
|
| - * text nodes are (incorrectly) not stripped in some cases.
|
| - *
|
| - * Example: : <foo> <!-- bar -->zoo</foo>
|
| - * Corrent (strict) result: <foo> zoo</foo>
|
| - * Incorrect (old) result : <foo>zoo</foo>
|
| - *
|
| - * NOTE that we *will* merge adjacent text-nodes if
|
| - * they are in xsl:text.
|
| - * Example, the following:
|
| - * <xsl:text> <!-- bar -->zoo<xsl:text>
|
| - * will result in both cases in:
|
| - * <xsl:text> zoo<xsl:text>
|
| - */
|
| - cur->type = XML_TEXT_NODE;
|
| - if ((strictWhitespace != 0) || (inXSLText != 0)) {
|
| - /*
|
| - * New behaviour; merge nodes.
|
| - */
|
| - if (textNode == NULL)
|
| - textNode = cur;
|
| - else {
|
| - if (cur->content != NULL)
|
| - xmlNodeAddContent(textNode, cur->content);
|
| - deleteNode = cur;
|
| - }
|
| - if ((cur->next == NULL) ||
|
| - (cur->next->type == XML_ELEMENT_NODE))
|
| - goto end_of_text;
|
| - else
|
| - goto next_sibling;
|
| - } else {
|
| - /*
|
| - * Old behaviour.
|
| - */
|
| - if (textNode == NULL)
|
| - textNode = cur;
|
| - goto end_of_text;
|
| - }
|
| - } else if ((cur->type == XML_COMMENT_NODE) ||
|
| - (cur->type == XML_PI_NODE))
|
| - {
|
| - /*
|
| - * Remove processing instructions and comments.
|
| - */
|
| - deleteNode = cur;
|
| - if ((cur->next == NULL) ||
|
| - (cur->next->type == XML_ELEMENT_NODE))
|
| - goto end_of_text;
|
| - else
|
| - goto next_sibling;
|
| - } else {
|
| - textNode = NULL;
|
| - /*
|
| - * Invalid node-type for this data-model.
|
| - */
|
| - xsltTransformError(NULL, style, cur,
|
| - "Invalid type of node for the XSLT data model.\n");
|
| - cctxt->style->errors++;
|
| - goto next_sibling;
|
| - }
|
| -
|
| -end_of_text:
|
| - if (textNode) {
|
| - value = textNode->content;
|
| - /*
|
| - * At this point all adjacent text/CDATA-section nodes
|
| - * have been merged.
|
| - *
|
| - * Strip whitespace-only text-nodes.
|
| - * (cctxt->inode->stripWhitespace)
|
| - */
|
| - if ((value == NULL) || (*value == 0) ||
|
| - (((cctxt->inode->stripWhitespace) ||
|
| - (! cctxt->inode->preserveWhitespace)) &&
|
| - IS_BLANK(*value) &&
|
| - xsltIsBlank(value)))
|
| - {
|
| - if (textNode != cur) {
|
| - xmlUnlinkNode(textNode);
|
| - xmlFreeNode(textNode);
|
| - } else
|
| - deleteNode = textNode;
|
| - textNode = NULL;
|
| - goto next_sibling;
|
| - }
|
| - /*
|
| - * Convert CDATA-section nodes to text-nodes.
|
| - * TODO: Can this produce problems?
|
| - */
|
| - if (textNode->type != XML_TEXT_NODE) {
|
| - textNode->type = XML_TEXT_NODE;
|
| - textNode->name = xmlStringText;
|
| - }
|
| - if (internalize &&
|
| - (textNode->content != NULL) &&
|
| - (!xmlDictOwns(style->dict, textNode->content)))
|
| - {
|
| - /*
|
| - * Internalize the string.
|
| - */
|
| - value = (xmlChar *) xmlDictLookup(style->dict,
|
| - textNode->content, -1);
|
| - xmlNodeSetContent(textNode, NULL);
|
| - textNode->content = value;
|
| - }
|
| - textNode = NULL;
|
| - /*
|
| - * Note that "disable-output-escaping" of the xsl:text
|
| - * element will be applied at a later level, when
|
| - * XSLT elements are processed.
|
| - */
|
| - }
|
| -
|
| -next_sibling:
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - xsltCompilerNodePop(cctxt, cur);
|
| - }
|
| - if (cur == node)
|
| - break;
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - } else {
|
| - cur = cur->parent;
|
| - inXSLText = 0;
|
| - goto next_sibling;
|
| - };
|
| - }
|
| - if (deleteNode != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParsePreprocessStylesheetTree: removing node\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - }
|
| - return(0);
|
| -
|
| -internal_err:
|
| - return(-1);
|
| -}
|
| -
|
| -#endif /* XSLT_REFACTORED */
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -#else
|
| -static void
|
| -xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur)
|
| -{
|
| - xmlNodePtr deleteNode, styleelem;
|
| - int internalize = 0;
|
| -
|
| - if ((style == NULL) || (cur == NULL))
|
| - return;
|
| -
|
| - if ((cur->doc != NULL) && (style->dict != NULL) &&
|
| - (cur->doc->dict == style->dict))
|
| - internalize = 1;
|
| - else
|
| - style->internalized = 0;
|
| -
|
| - if ((cur != NULL) && (IS_XSLT_ELEM(cur)) &&
|
| - (IS_XSLT_NAME(cur, "stylesheet"))) {
|
| - styleelem = cur;
|
| - } else {
|
| - styleelem = NULL;
|
| - }
|
| -
|
| - /*
|
| - * This content comes from the stylesheet
|
| - * For stylesheets, the set of whitespace-preserving
|
| - * element names consists of just xsl:text.
|
| - */
|
| - deleteNode = NULL;
|
| - while (cur != NULL) {
|
| - if (deleteNode != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_BLANKS
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltPreprocessStylesheet: removing ignorable blank node\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - deleteNode = NULL;
|
| - }
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - int exclPrefixes;
|
| - /*
|
| - * Internalize attributes values.
|
| - */
|
| - if ((internalize) && (cur->properties != NULL)) {
|
| - xmlAttrPtr attr = cur->properties;
|
| - xmlNodePtr txt;
|
| -
|
| - while (attr != NULL) {
|
| - txt = attr->children;
|
| - if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
| - (txt->content != NULL) &&
|
| - (!xmlDictOwns(style->dict, txt->content)))
|
| - {
|
| - xmlChar *tmp;
|
| -
|
| - /*
|
| - * internalize the text string, goal is to speed
|
| - * up operations and minimize used space by compiled
|
| - * stylesheets.
|
| - */
|
| - tmp = (xmlChar *) xmlDictLookup(style->dict,
|
| - txt->content, -1);
|
| - if (tmp != txt->content) {
|
| - xmlNodeSetContent(txt, NULL);
|
| - txt->content = tmp;
|
| - }
|
| - }
|
| - attr = attr->next;
|
| - }
|
| - }
|
| - if (IS_XSLT_ELEM(cur)) {
|
| - exclPrefixes = 0;
|
| - if (IS_XSLT_NAME(cur, "text")) {
|
| - for (;exclPrefixes > 0;exclPrefixes--)
|
| - exclPrefixPop(style);
|
| - goto skip_children;
|
| - }
|
| - } else {
|
| - exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0);
|
| - }
|
| -
|
| - if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) {
|
| - xmlNsPtr ns = cur->nsDef, prev = NULL, next;
|
| - xmlNodePtr root = NULL;
|
| - int i, moved;
|
| -
|
| - root = xmlDocGetRootElement(cur->doc);
|
| - if ((root != NULL) && (root != cur)) {
|
| - while (ns != NULL) {
|
| - moved = 0;
|
| - next = ns->next;
|
| - for (i = 0;i < style->exclPrefixNr;i++) {
|
| - if ((ns->prefix != NULL) &&
|
| - (xmlStrEqual(ns->href,
|
| - style->exclPrefixTab[i]))) {
|
| - /*
|
| - * Move the namespace definition on the root
|
| - * element to avoid duplicating it without
|
| - * loosing it.
|
| - */
|
| - if (prev == NULL) {
|
| - cur->nsDef = ns->next;
|
| - } else {
|
| - prev->next = ns->next;
|
| - }
|
| - ns->next = root->nsDef;
|
| - root->nsDef = ns;
|
| - moved = 1;
|
| - break;
|
| - }
|
| - }
|
| - if (moved == 0)
|
| - prev = ns;
|
| - ns = next;
|
| - }
|
| - }
|
| - }
|
| - /*
|
| - * If we have prefixes locally, recurse and pop them up when
|
| - * going back
|
| - */
|
| - if (exclPrefixes > 0) {
|
| - xsltPreprocessStylesheet(style, cur->children);
|
| - for (;exclPrefixes > 0;exclPrefixes--)
|
| - exclPrefixPop(style);
|
| - goto skip_children;
|
| - }
|
| - } else if (cur->type == XML_TEXT_NODE) {
|
| - if (IS_BLANK_NODE(cur)) {
|
| - if (xmlNodeGetSpacePreserve(cur->parent) != 1) {
|
| - deleteNode = cur;
|
| - }
|
| - } else if ((cur->content != NULL) && (internalize) &&
|
| - (!xmlDictOwns(style->dict, cur->content))) {
|
| - xmlChar *tmp;
|
| -
|
| - /*
|
| - * internalize the text string, goal is to speed
|
| - * up operations and minimize used space by compiled
|
| - * stylesheets.
|
| - */
|
| - tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1);
|
| - xmlNodeSetContent(cur, NULL);
|
| - cur->content = tmp;
|
| - }
|
| - } else if ((cur->type != XML_ELEMENT_NODE) &&
|
| - (cur->type != XML_CDATA_SECTION_NODE)) {
|
| - deleteNode = cur;
|
| - goto skip_children;
|
| - }
|
| -
|
| - /*
|
| - * Skip to next node. In case of a namespaced element children of
|
| - * the stylesheet and not in the XSLT namespace and not an extension
|
| - * element, ignore its content.
|
| - */
|
| - if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) &&
|
| - (styleelem != NULL) && (cur->parent == styleelem) &&
|
| - (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) &&
|
| - (!xsltCheckExtURI(style, cur->ns->href))) {
|
| - goto skip_children;
|
| - } else if (cur->children != NULL) {
|
| - if ((cur->children->type != XML_ENTITY_DECL) &&
|
| - (cur->children->type != XML_ENTITY_REF_NODE) &&
|
| - (cur->children->type != XML_ENTITY_NODE)) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - }
|
| -
|
| -skip_children:
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - do {
|
| -
|
| - cur = cur->parent;
|
| - if (cur == NULL)
|
| - break;
|
| - if (cur == (xmlNodePtr) style->doc) {
|
| - cur = NULL;
|
| - break;
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - break;
|
| - }
|
| - } while (cur != NULL);
|
| - }
|
| - if (deleteNode != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltPreprocessStylesheet: removing ignorable blank node\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - }
|
| -}
|
| -#endif /* end of else XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltGatherNamespaces:
|
| - * @style: the XSLT stylesheet
|
| - *
|
| - * Browse the stylesheet and build the namspace hash table which
|
| - * will be used for XPath interpretation. If needed do a bit of normalization
|
| - */
|
| -
|
| -static void
|
| -xsltGatherNamespaces(xsltStylesheetPtr style) {
|
| - xmlNodePtr cur;
|
| - const xmlChar *URI;
|
| -
|
| - if (style == NULL)
|
| - return;
|
| - /*
|
| - * TODO: basically if the stylesheet uses the same prefix for different
|
| - * patterns, well they may be in problem, hopefully they will get
|
| - * a warning first.
|
| - */
|
| - /*
|
| - * TODO: Eliminate the use of the hash for XPath expressions.
|
| - * An expression should be evaluated in the context of the in-scope
|
| - * namespaces; eliminate the restriction of an XML document to contain
|
| - * no duplicate prefixes for different namespace names.
|
| - *
|
| - */
|
| - cur = xmlDocGetRootElement(style->doc);
|
| - while (cur != NULL) {
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - xmlNsPtr ns = cur->nsDef;
|
| - while (ns != NULL) {
|
| - if (ns->prefix != NULL) {
|
| - if (style->nsHash == NULL) {
|
| - style->nsHash = xmlHashCreate(10);
|
| - if (style->nsHash == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltGatherNamespaces: failed to create hash table\n");
|
| - style->errors++;
|
| - return;
|
| - }
|
| - }
|
| - URI = xmlHashLookup(style->nsHash, ns->prefix);
|
| - if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Namespaces prefix %s used for multiple namespaces\n",ns->prefix);
|
| - style->warnings++;
|
| - } else if (URI == NULL) {
|
| - xmlHashUpdateEntry(style->nsHash, ns->prefix,
|
| - (void *) ns->href, (xmlHashDeallocator)xmlFree);
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "Added namespace: %s mapped to %s\n", ns->prefix, ns->href);
|
| -#endif
|
| - }
|
| - }
|
| - ns = ns->next;
|
| - }
|
| - }
|
| -
|
| - /*
|
| - * Skip to next node
|
| - */
|
| - if (cur->children != NULL) {
|
| - if (cur->children->type != XML_ENTITY_DECL) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| -
|
| - do {
|
| - cur = cur->parent;
|
| - if (cur == NULL)
|
| - break;
|
| - if (cur == (xmlNodePtr) style->doc) {
|
| - cur = NULL;
|
| - break;
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - break;
|
| - }
|
| - } while (cur != NULL);
|
| - }
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -
|
| -static xsltStyleType
|
| -xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr node)
|
| -{
|
| - if ((node == NULL) || (node->type != XML_ELEMENT_NODE) ||
|
| - (node->name == NULL))
|
| - return(0);
|
| -
|
| - if (node->name[0] == 'a') {
|
| - if (IS_XSLT_NAME(node, "apply-templates"))
|
| - return(XSLT_FUNC_APPLYTEMPLATES);
|
| - else if (IS_XSLT_NAME(node, "attribute"))
|
| - return(XSLT_FUNC_ATTRIBUTE);
|
| - else if (IS_XSLT_NAME(node, "apply-imports"))
|
| - return(XSLT_FUNC_APPLYIMPORTS);
|
| - else if (IS_XSLT_NAME(node, "attribute-set"))
|
| - return(0);
|
| -
|
| - } else if (node->name[0] == 'c') {
|
| - if (IS_XSLT_NAME(node, "choose"))
|
| - return(XSLT_FUNC_CHOOSE);
|
| - else if (IS_XSLT_NAME(node, "copy"))
|
| - return(XSLT_FUNC_COPY);
|
| - else if (IS_XSLT_NAME(node, "copy-of"))
|
| - return(XSLT_FUNC_COPYOF);
|
| - else if (IS_XSLT_NAME(node, "call-template"))
|
| - return(XSLT_FUNC_CALLTEMPLATE);
|
| - else if (IS_XSLT_NAME(node, "comment"))
|
| - return(XSLT_FUNC_COMMENT);
|
| -
|
| - } else if (node->name[0] == 'd') {
|
| - if (IS_XSLT_NAME(node, "document"))
|
| - return(XSLT_FUNC_DOCUMENT);
|
| - else if (IS_XSLT_NAME(node, "decimal-format"))
|
| - return(0);
|
| -
|
| - } else if (node->name[0] == 'e') {
|
| - if (IS_XSLT_NAME(node, "element"))
|
| - return(XSLT_FUNC_ELEMENT);
|
| -
|
| - } else if (node->name[0] == 'f') {
|
| - if (IS_XSLT_NAME(node, "for-each"))
|
| - return(XSLT_FUNC_FOREACH);
|
| - else if (IS_XSLT_NAME(node, "fallback"))
|
| - return(XSLT_FUNC_FALLBACK);
|
| -
|
| - } else if (*(node->name) == 'i') {
|
| - if (IS_XSLT_NAME(node, "if"))
|
| - return(XSLT_FUNC_IF);
|
| - else if (IS_XSLT_NAME(node, "include"))
|
| - return(0);
|
| - else if (IS_XSLT_NAME(node, "import"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 'k') {
|
| - if (IS_XSLT_NAME(node, "key"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 'm') {
|
| - if (IS_XSLT_NAME(node, "message"))
|
| - return(XSLT_FUNC_MESSAGE);
|
| -
|
| - } else if (*(node->name) == 'n') {
|
| - if (IS_XSLT_NAME(node, "number"))
|
| - return(XSLT_FUNC_NUMBER);
|
| - else if (IS_XSLT_NAME(node, "namespace-alias"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 'o') {
|
| - if (IS_XSLT_NAME(node, "otherwise"))
|
| - return(XSLT_FUNC_OTHERWISE);
|
| - else if (IS_XSLT_NAME(node, "output"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 'p') {
|
| - if (IS_XSLT_NAME(node, "param"))
|
| - return(XSLT_FUNC_PARAM);
|
| - else if (IS_XSLT_NAME(node, "processing-instruction"))
|
| - return(XSLT_FUNC_PI);
|
| - else if (IS_XSLT_NAME(node, "preserve-space"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 's') {
|
| - if (IS_XSLT_NAME(node, "sort"))
|
| - return(XSLT_FUNC_SORT);
|
| - else if (IS_XSLT_NAME(node, "strip-space"))
|
| - return(0);
|
| - else if (IS_XSLT_NAME(node, "stylesheet"))
|
| - return(0);
|
| -
|
| - } else if (node->name[0] == 't') {
|
| - if (IS_XSLT_NAME(node, "text"))
|
| - return(XSLT_FUNC_TEXT);
|
| - else if (IS_XSLT_NAME(node, "template"))
|
| - return(0);
|
| - else if (IS_XSLT_NAME(node, "transform"))
|
| - return(0);
|
| -
|
| - } else if (*(node->name) == 'v') {
|
| - if (IS_XSLT_NAME(node, "value-of"))
|
| - return(XSLT_FUNC_VALUEOF);
|
| - else if (IS_XSLT_NAME(node, "variable"))
|
| - return(XSLT_FUNC_VARIABLE);
|
| -
|
| - } else if (*(node->name) == 'w') {
|
| - if (IS_XSLT_NAME(node, "when"))
|
| - return(XSLT_FUNC_WHEN);
|
| - if (IS_XSLT_NAME(node, "with-param"))
|
| - return(XSLT_FUNC_WITHPARAM);
|
| - }
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseAnyXSLTElem:
|
| - *
|
| - * @cctxt: the compilation context
|
| - * @elem: the element node of the XSLT instruction
|
| - *
|
| - * Parses, validates the content models and compiles XSLT instructions.
|
| - *
|
| - * Returns 0 if everything's fine;
|
| - * -1 on API or internal errors.
|
| - */
|
| -int
|
| -xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
|
| -{
|
| - if ((cctxt == NULL) || (elem == NULL) ||
|
| - (elem->type != XML_ELEMENT_NODE))
|
| - return(-1);
|
| -
|
| - elem->psvi = NULL;
|
| -
|
| - if (! (IS_XSLT_ELEM_FAST(elem)))
|
| - return(-1);
|
| - /*
|
| - * Detection of handled content of extension instructions.
|
| - */
|
| - if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
|
| - cctxt->inode->extContentHandled = 1;
|
| - }
|
| -
|
| - xsltCompilerNodePush(cctxt, elem);
|
| - /*
|
| - * URGENT TODO: Find a way to speed up this annoying redundant
|
| - * textual node-name and namespace comparison.
|
| - */
|
| - if (cctxt->inode->prev->curChildType != 0)
|
| - cctxt->inode->type = cctxt->inode->prev->curChildType;
|
| - else
|
| - cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem);
|
| - /*
|
| - * Update the in-scope namespaces if needed.
|
| - */
|
| - if (elem->nsDef != NULL)
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, elem);
|
| - /*
|
| - * xsltStylePreCompute():
|
| - * This will compile the information found on the current
|
| - * element's attributes. NOTE that this won't process the
|
| - * children of the instruction.
|
| - */
|
| - xsltStylePreCompute(cctxt->style, elem);
|
| - /*
|
| - * TODO: How to react on errors in xsltStylePreCompute() ?
|
| - */
|
| -
|
| - /*
|
| - * Validate the content model of the XSLT-element.
|
| - */
|
| - switch (cctxt->inode->type) {
|
| - case XSLT_FUNC_APPLYIMPORTS:
|
| - /* EMPTY */
|
| - goto empty_content;
|
| - case XSLT_FUNC_APPLYTEMPLATES:
|
| - /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
|
| - goto apply_templates;
|
| - case XSLT_FUNC_ATTRIBUTE:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_CALLTEMPLATE:
|
| - /* <!-- Content: xsl:with-param* --> */
|
| - goto call_template;
|
| - case XSLT_FUNC_CHOOSE:
|
| - /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
|
| - goto choose;
|
| - case XSLT_FUNC_COMMENT:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_COPY:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_COPYOF:
|
| - /* EMPTY */
|
| - goto empty_content;
|
| - case XSLT_FUNC_DOCUMENT: /* Extra one */
|
| - /* ?? template ?? */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_ELEMENT:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_FALLBACK:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_FOREACH:
|
| - /* <!-- Content: (xsl:sort*, template) --> */
|
| - goto for_each;
|
| - case XSLT_FUNC_IF:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_OTHERWISE:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_MESSAGE:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_NUMBER:
|
| - /* EMPTY */
|
| - goto empty_content;
|
| - case XSLT_FUNC_PARAM:
|
| - /*
|
| - * Check for redefinition.
|
| - */
|
| - if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
|
| - xsltVarInfoPtr ivar = cctxt->ivar;
|
| -
|
| - do {
|
| - if ((ivar->name ==
|
| - ((xsltStyleItemParamPtr) elem->psvi)->name) &&
|
| - (ivar->nsName ==
|
| - ((xsltStyleItemParamPtr) elem->psvi)->ns))
|
| - {
|
| - elem->psvi = NULL;
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Redefinition of variable or parameter '%s'.\n",
|
| - ivar->name);
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - ivar = ivar->prev;
|
| - } while (ivar != NULL);
|
| - }
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_PI:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_SORT:
|
| - /* EMPTY */
|
| - goto empty_content;
|
| - case XSLT_FUNC_TEXT:
|
| - /* <!-- Content: #PCDATA --> */
|
| - goto text;
|
| - case XSLT_FUNC_VALUEOF:
|
| - /* EMPTY */
|
| - goto empty_content;
|
| - case XSLT_FUNC_VARIABLE:
|
| - /*
|
| - * Check for redefinition.
|
| - */
|
| - if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) {
|
| - xsltVarInfoPtr ivar = cctxt->ivar;
|
| -
|
| - do {
|
| - if ((ivar->name ==
|
| - ((xsltStyleItemVariablePtr) elem->psvi)->name) &&
|
| - (ivar->nsName ==
|
| - ((xsltStyleItemVariablePtr) elem->psvi)->ns))
|
| - {
|
| - elem->psvi = NULL;
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "Redefinition of variable or parameter '%s'.\n",
|
| - ivar->name);
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - ivar = ivar->prev;
|
| - } while (ivar != NULL);
|
| - }
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_WHEN:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - case XSLT_FUNC_WITHPARAM:
|
| - /* <!-- Content: template --> */
|
| - goto sequence_constructor;
|
| - default:
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n",
|
| - elem->name);
|
| -#endif
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "xsltParseXSLTNode: Internal error; "
|
| - "unhandled XSLT element '%s'.\n", elem->name);
|
| - cctxt->style->errors++;
|
| - goto internal_err;
|
| - }
|
| -
|
| -apply_templates:
|
| - /* <!-- Content: (xsl:sort | xsl:with-param)* --> */
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - do {
|
| - if (child->type == XML_ELEMENT_NODE) {
|
| - if (IS_XSLT_ELEM_FAST(child)) {
|
| - if (xmlStrEqual(child->name, BAD_CAST "with-param")) {
|
| - cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else if (xmlStrEqual(child->name, BAD_CAST "sort")) {
|
| - cctxt->inode->curChildType = XSLT_FUNC_SORT;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else
|
| - xsltParseContentError(cctxt->style, child);
|
| - } else
|
| - xsltParseContentError(cctxt->style, child);
|
| - }
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - }
|
| - goto exit;
|
| -
|
| -call_template:
|
| - /* <!-- Content: xsl:with-param* --> */
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - do {
|
| - if (child->type == XML_ELEMENT_NODE) {
|
| - if (IS_XSLT_ELEM_FAST(child)) {
|
| - xsltStyleType type;
|
| -
|
| - type = xsltGetXSLTElementTypeByNode(cctxt, child);
|
| - if (type == XSLT_FUNC_WITHPARAM) {
|
| - cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else {
|
| - xsltParseContentError(cctxt->style, child);
|
| - }
|
| - } else
|
| - xsltParseContentError(cctxt->style, child);
|
| - }
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - }
|
| - goto exit;
|
| -
|
| -text:
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - do {
|
| - if ((child->type != XML_TEXT_NODE) &&
|
| - (child->type != XML_CDATA_SECTION_NODE))
|
| - {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "The XSLT 'text' element must have only character "
|
| - "data as content.\n");
|
| - }
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - }
|
| - goto exit;
|
| -
|
| -empty_content:
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - /*
|
| - * Relaxed behaviour: we will allow whitespace-only text-nodes.
|
| - */
|
| - do {
|
| - if (((child->type != XML_TEXT_NODE) &&
|
| - (child->type != XML_CDATA_SECTION_NODE)) ||
|
| - (! IS_BLANK_NODE(child)))
|
| - {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "This XSLT element must have no content.\n");
|
| - cctxt->style->errors++;
|
| - break;
|
| - }
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - }
|
| - goto exit;
|
| -
|
| -choose:
|
| - /* <!-- Content: (xsl:when+, xsl:otherwise?) --> */
|
| - /*
|
| - * TODO: text-nodes in between are *not* allowed in XSLT 1.0.
|
| - * The old behaviour did not check this.
|
| - * NOTE: In XSLT 2.0 they are stripped beforehand
|
| - * if whitespace-only (regardless of xml:space).
|
| - */
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - int nbWhen = 0, nbOtherwise = 0, err = 0;
|
| - do {
|
| - if (child->type == XML_ELEMENT_NODE) {
|
| - if (IS_XSLT_ELEM_FAST(child)) {
|
| - xsltStyleType type;
|
| -
|
| - type = xsltGetXSLTElementTypeByNode(cctxt, child);
|
| - if (type == XSLT_FUNC_WHEN) {
|
| - nbWhen++;
|
| - if (nbOtherwise) {
|
| - xsltParseContentError(cctxt->style, child);
|
| - err = 1;
|
| - break;
|
| - }
|
| - cctxt->inode->curChildType = XSLT_FUNC_WHEN;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else if (type == XSLT_FUNC_OTHERWISE) {
|
| - if (! nbWhen) {
|
| - xsltParseContentError(cctxt->style, child);
|
| - err = 1;
|
| - break;
|
| - }
|
| - if (nbOtherwise) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "The XSLT 'choose' element must not contain "
|
| - "more than one XSLT 'otherwise' element.\n");
|
| - cctxt->style->errors++;
|
| - err = 1;
|
| - break;
|
| - }
|
| - nbOtherwise++;
|
| - cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else
|
| - xsltParseContentError(cctxt->style, child);
|
| - } else
|
| - xsltParseContentError(cctxt->style, child);
|
| - }
|
| - /*
|
| - else
|
| - xsltParseContentError(cctxt, child);
|
| - */
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - if ((! err) && (! nbWhen)) {
|
| - xsltTransformError(NULL, cctxt->style, elem,
|
| - "The XSLT element 'choose' must contain at least one "
|
| - "XSLT element 'when'.\n");
|
| - cctxt->style->errors++;
|
| - }
|
| - }
|
| - goto exit;
|
| -
|
| -for_each:
|
| - /* <!-- Content: (xsl:sort*, template) --> */
|
| - /*
|
| - * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0.
|
| - * The old behaviour did not allow this, but it catched this
|
| - * only at transformation-time.
|
| - * In XSLT 2.0 they are stripped beforehand if whitespace-only
|
| - * (regardless of xml:space).
|
| - */
|
| - if (elem->children != NULL) {
|
| - xmlNodePtr child = elem->children;
|
| - /*
|
| - * Parse xsl:sort first.
|
| - */
|
| - do {
|
| - if ((child->type == XML_ELEMENT_NODE) &&
|
| - IS_XSLT_ELEM_FAST(child))
|
| - {
|
| - if (xsltGetXSLTElementTypeByNode(cctxt, child) ==
|
| - XSLT_FUNC_SORT)
|
| - {
|
| - cctxt->inode->curChildType = XSLT_FUNC_SORT;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - } else
|
| - break;
|
| - } else
|
| - break;
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - /*
|
| - * Parse the sequece constructor.
|
| - */
|
| - if (child != NULL)
|
| - xsltParseSequenceConstructor(cctxt, child);
|
| - }
|
| - goto exit;
|
| -
|
| -sequence_constructor:
|
| - /*
|
| - * Parse the sequence constructor.
|
| - */
|
| - if (elem->children != NULL)
|
| - xsltParseSequenceConstructor(cctxt, elem->children);
|
| -
|
| - /*
|
| - * Register information for vars/params. Only needed if there
|
| - * are any following siblings.
|
| - */
|
| - if ((elem->next != NULL) &&
|
| - ((cctxt->inode->type == XSLT_FUNC_VARIABLE) ||
|
| - (cctxt->inode->type == XSLT_FUNC_PARAM)))
|
| - {
|
| - if ((elem->psvi != NULL) &&
|
| - (((xsltStyleBasicItemVariablePtr) elem->psvi)->name))
|
| - {
|
| - xsltCompilerVarInfoPush(cctxt, elem,
|
| - ((xsltStyleBasicItemVariablePtr) elem->psvi)->name,
|
| - ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns);
|
| - }
|
| - }
|
| -
|
| -error:
|
| -exit:
|
| - xsltCompilerNodePop(cctxt, elem);
|
| - return(0);
|
| -
|
| -internal_err:
|
| - xsltCompilerNodePop(cctxt, elem);
|
| - return(-1);
|
| -}
|
| -
|
| -/**
|
| - * xsltForwardsCompatUnkownItemCreate:
|
| - *
|
| - * @cctxt: the compilation context
|
| - *
|
| - * Creates a compiled representation of the unknown
|
| - * XSLT instruction.
|
| - *
|
| - * Returns the compiled representation.
|
| - */
|
| -static xsltStyleItemUknownPtr
|
| -xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
|
| -{
|
| - xsltStyleItemUknownPtr item;
|
| -
|
| - item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown));
|
| - if (item == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, NULL,
|
| - "Internal error in xsltForwardsCompatUnkownItemCreate(): "
|
| - "Failed to allocate memory.\n");
|
| - cctxt->style->errors++;
|
| - return(NULL);
|
| - }
|
| - memset(item, 0, sizeof(xsltStyleItemUknown));
|
| - item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT;
|
| - /*
|
| - * Store it in the stylesheet.
|
| - */
|
| - item->next = cctxt->style->preComps;
|
| - cctxt->style->preComps = (xsltElemPreCompPtr) item;
|
| - return(item);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseUnknownXSLTElem:
|
| - *
|
| - * @cctxt: the compilation context
|
| - * @node: the element of the unknown XSLT instruction
|
| - *
|
| - * Parses an unknown XSLT element.
|
| - * If forwards compatible mode is enabled this will allow
|
| - * such an unknown XSLT and; otherwise it is rejected.
|
| - *
|
| - * Returns 1 in the unknown XSLT instruction is rejected,
|
| - * 0 if everything's fine and
|
| - * -1 on API or internal errors.
|
| - */
|
| -static int
|
| -xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr node)
|
| -{
|
| - if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
|
| - return(-1);
|
| -
|
| - /*
|
| - * Detection of handled content of extension instructions.
|
| - */
|
| - if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
|
| - cctxt->inode->extContentHandled = 1;
|
| - }
|
| - if (cctxt->inode->forwardsCompat == 0) {
|
| - /*
|
| - * We are not in forwards-compatible mode, so raise an error.
|
| - */
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Unknown XSLT element '%s'.\n", node->name);
|
| - cctxt->style->errors++;
|
| - return(1);
|
| - }
|
| - /*
|
| - * Forwards-compatible mode.
|
| - * ------------------------
|
| - *
|
| - * Parse/compile xsl:fallback elements.
|
| - *
|
| - * QUESTION: Do we have to raise an error if there's no xsl:fallback?
|
| - * ANSWER: No, since in the stylesheet the fallback behaviour might
|
| - * also be provided by using the XSLT function "element-available".
|
| - */
|
| - if (cctxt->unknownItem == NULL) {
|
| - /*
|
| - * Create a singleton for all unknown XSLT instructions.
|
| - */
|
| - cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt);
|
| - if (cctxt->unknownItem == NULL) {
|
| - node->psvi = NULL;
|
| - return(-1);
|
| - }
|
| - }
|
| - node->psvi = cctxt->unknownItem;
|
| - if (node->children == NULL)
|
| - return(0);
|
| - else {
|
| - xmlNodePtr child = node->children;
|
| -
|
| - xsltCompilerNodePush(cctxt, node);
|
| - /*
|
| - * Update the in-scope namespaces if needed.
|
| - */
|
| - if (node->nsDef != NULL)
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, node);
|
| - /*
|
| - * Parse all xsl:fallback children.
|
| - */
|
| - do {
|
| - if ((child->type == XML_ELEMENT_NODE) &&
|
| - IS_XSLT_ELEM_FAST(child) &&
|
| - IS_XSLT_NAME(child, "fallback"))
|
| - {
|
| - cctxt->inode->curChildType = XSLT_FUNC_FALLBACK;
|
| - xsltParseAnyXSLTElem(cctxt, child);
|
| - }
|
| - child = child->next;
|
| - } while (child != NULL);
|
| -
|
| - xsltCompilerNodePop(cctxt, node);
|
| - }
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseSequenceConstructor:
|
| - *
|
| - * @cctxt: the compilation context
|
| - * @cur: the start-node of the content to be parsed
|
| - *
|
| - * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms).
|
| - * This will additionally remove xsl:text elements from the tree.
|
| - */
|
| -void
|
| -xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
|
| -{
|
| - xsltStyleType type;
|
| - xmlNodePtr deleteNode = NULL;
|
| -
|
| - if (cctxt == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext,
|
| - "xsltParseSequenceConstructor: Bad arguments\n");
|
| - cctxt->style->errors++;
|
| - return;
|
| - }
|
| - /*
|
| - * Detection of handled content of extension instructions.
|
| - */
|
| - if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
|
| - cctxt->inode->extContentHandled = 1;
|
| - }
|
| - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
|
| - return;
|
| - /*
|
| - * This is the content reffered to as a "template".
|
| - * E.g. an xsl:element has such content model:
|
| - * <xsl:element
|
| - * name = { qname }
|
| - * namespace = { uri-reference }
|
| - * use-attribute-sets = qnames>
|
| - * <!-- Content: template -->
|
| - *
|
| - * NOTE that in XSLT-2 the term "template" was abandoned due to
|
| - * confusion with xsl:template and the term "sequence constructor"
|
| - * was introduced instead.
|
| - *
|
| - * The following XSLT-instructions are allowed to appear:
|
| - * xsl:apply-templates, xsl:call-template, xsl:apply-imports,
|
| - * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number,
|
| - * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable,
|
| - * xsl:message, xsl:fallback,
|
| - * xsl:processing-instruction, xsl:comment, xsl:element
|
| - * xsl:attribute.
|
| - * Additional allowed content:
|
| - * 1) extension instructions
|
| - * 2) literal result elements
|
| - * 3) PCDATA
|
| - *
|
| - * NOTE that this content model does *not* allow xsl:param.
|
| - */
|
| - while (cur != NULL) {
|
| - if (deleteNode != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_BLANKS
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseSequenceConstructor: removing xsl:text element\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - deleteNode = NULL;
|
| - }
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| -
|
| - if (cur->psvi == xsltXSLTTextMarker) {
|
| - /*
|
| - * xsl:text elements
|
| - * --------------------------------------------------------
|
| - */
|
| - xmlNodePtr tmp;
|
| -
|
| - cur->psvi = NULL;
|
| - /*
|
| - * Mark the xsl:text element for later deletion.
|
| - */
|
| - deleteNode = cur;
|
| - /*
|
| - * Validate content.
|
| - */
|
| - tmp = cur->children;
|
| - if (tmp) {
|
| - /*
|
| - * We don't expect more than one text-node in the
|
| - * content, since we already merged adjacent
|
| - * text/CDATA-nodes and eliminated PI/comment-nodes.
|
| - */
|
| - if ((tmp->type == XML_TEXT_NODE) ||
|
| - (tmp->next == NULL))
|
| - {
|
| - /*
|
| - * Leave the contained text-node in the tree.
|
| - */
|
| - xmlUnlinkNode(tmp);
|
| - xmlAddPrevSibling(cur, tmp);
|
| - } else {
|
| - tmp = NULL;
|
| - xsltTransformError(NULL, cctxt->style, cur,
|
| - "Element 'xsl:text': Invalid type "
|
| - "of node found in content.\n");
|
| - cctxt->style->errors++;
|
| - }
|
| - }
|
| - if (cur->properties) {
|
| - xmlAttrPtr attr;
|
| - /*
|
| - * TODO: We need to report errors for
|
| - * invalid attrs.
|
| - */
|
| - attr = cur->properties;
|
| - do {
|
| - if ((attr->ns == NULL) &&
|
| - (attr->name != NULL) &&
|
| - (attr->name[0] == 'd') &&
|
| - xmlStrEqual(attr->name,
|
| - BAD_CAST "disable-output-escaping"))
|
| - {
|
| - /*
|
| - * Attr "disable-output-escaping".
|
| - * XSLT-2: This attribute is deprecated.
|
| - */
|
| - if ((attr->children != NULL) &&
|
| - xmlStrEqual(attr->children->content,
|
| - BAD_CAST "yes"))
|
| - {
|
| - /*
|
| - * Disable output escaping for this
|
| - * text node.
|
| - */
|
| - if (tmp)
|
| - tmp->name = xmlStringTextNoenc;
|
| - } else if ((attr->children == NULL) ||
|
| - (attr->children->content == NULL) ||
|
| - (!xmlStrEqual(attr->children->content,
|
| - BAD_CAST "no")))
|
| - {
|
| - xsltTransformError(NULL, cctxt->style,
|
| - cur,
|
| - "Attribute 'disable-output-escaping': "
|
| - "Invalid value. Expected is "
|
| - "'yes' or 'no'.\n");
|
| - cctxt->style->errors++;
|
| - }
|
| - break;
|
| - }
|
| - attr = attr->next;
|
| - } while (attr != NULL);
|
| - }
|
| - } else if (IS_XSLT_ELEM_FAST(cur)) {
|
| - /*
|
| - * TODO: Using the XSLT-marker is still not stable yet.
|
| - */
|
| - /* if (cur->psvi == xsltXSLTElemMarker) { */
|
| - /*
|
| - * XSLT instructions
|
| - * --------------------------------------------------------
|
| - */
|
| - cur->psvi = NULL;
|
| - type = xsltGetXSLTElementTypeByNode(cctxt, cur);
|
| - switch (type) {
|
| - case XSLT_FUNC_APPLYIMPORTS:
|
| - case XSLT_FUNC_APPLYTEMPLATES:
|
| - case XSLT_FUNC_ATTRIBUTE:
|
| - case XSLT_FUNC_CALLTEMPLATE:
|
| - case XSLT_FUNC_CHOOSE:
|
| - case XSLT_FUNC_COMMENT:
|
| - case XSLT_FUNC_COPY:
|
| - case XSLT_FUNC_COPYOF:
|
| - case XSLT_FUNC_DOCUMENT: /* Extra one */
|
| - case XSLT_FUNC_ELEMENT:
|
| - case XSLT_FUNC_FALLBACK:
|
| - case XSLT_FUNC_FOREACH:
|
| - case XSLT_FUNC_IF:
|
| - case XSLT_FUNC_MESSAGE:
|
| - case XSLT_FUNC_NUMBER:
|
| - case XSLT_FUNC_PI:
|
| - case XSLT_FUNC_TEXT:
|
| - case XSLT_FUNC_VALUEOF:
|
| - case XSLT_FUNC_VARIABLE:
|
| - /*
|
| - * Parse the XSLT element.
|
| - */
|
| - cctxt->inode->curChildType = type;
|
| - xsltParseAnyXSLTElem(cctxt, cur);
|
| - break;
|
| - default:
|
| - xsltParseUnknownXSLTElem(cctxt, cur);
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - } else {
|
| - /*
|
| - * Non-XSLT elements
|
| - * -----------------
|
| - */
|
| - xsltCompilerNodePush(cctxt, cur);
|
| - /*
|
| - * Update the in-scope namespaces if needed.
|
| - */
|
| - if (cur->nsDef != NULL)
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, cur);
|
| - /*
|
| - * The current element is either a literal result element
|
| - * or an extension instruction.
|
| - *
|
| - * Process attr "xsl:extension-element-prefixes".
|
| - * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be
|
| - * processed by the implementor of the extension function;
|
| - * i.e., it won't be handled by the XSLT processor.
|
| - */
|
| - /* SPEC 1.0:
|
| - * "exclude-result-prefixes" is only allowed on literal
|
| - * result elements and "xsl:exclude-result-prefixes"
|
| - * on xsl:stylesheet/xsl:transform.
|
| - * SPEC 2.0:
|
| - * "There are a number of standard attributes
|
| - * that may appear on any XSLT element: specifically
|
| - * version, exclude-result-prefixes,
|
| - * extension-element-prefixes, xpath-default-namespace,
|
| - * default-collation, and use-when."
|
| - *
|
| - * SPEC 2.0:
|
| - * For literal result elements:
|
| - * "xsl:version, xsl:exclude-result-prefixes,
|
| - * xsl:extension-element-prefixes,
|
| - * xsl:xpath-default-namespace,
|
| - * xsl:default-collation, or xsl:use-when."
|
| - */
|
| - if (cur->properties)
|
| - cctxt->inode->extElemNs =
|
| - xsltParseExtElemPrefixes(cctxt,
|
| - cur, cctxt->inode->extElemNs,
|
| - XSLT_ELEMENT_CATEGORY_LRE);
|
| - /*
|
| - * Eval if we have an extension instruction here.
|
| - */
|
| - if ((cur->ns != NULL) &&
|
| - (cctxt->inode->extElemNs != NULL) &&
|
| - (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1))
|
| - {
|
| - /*
|
| - * Extension instructions
|
| - * ----------------------------------------------------
|
| - * Mark the node information.
|
| - */
|
| - cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION;
|
| - cctxt->inode->extContentHandled = 0;
|
| - if (cur->psvi != NULL) {
|
| - cur->psvi = NULL;
|
| - /*
|
| - * TODO: Temporary sanity check.
|
| - */
|
| - xsltTransformError(NULL, cctxt->style, cur,
|
| - "Internal error in xsltParseSequenceConstructor(): "
|
| - "Occupied PSVI field.\n");
|
| - cctxt->style->errors++;
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - cur->psvi = (void *)
|
| - xsltPreComputeExtModuleElement(cctxt->style, cur);
|
| -
|
| - if (cur->psvi == NULL) {
|
| - /*
|
| - * OLD COMMENT: "Unknown element, maybe registered
|
| - * at the context level. Mark it for later
|
| - * recognition."
|
| - * QUESTION: What does the xsltExtMarker mean?
|
| - * ANSWER: It is used in
|
| - * xsltApplySequenceConstructor() at
|
| - * transformation-time to look out for extension
|
| - * registered in the transformation context.
|
| - */
|
| - cur->psvi = (void *) xsltExtMarker;
|
| - }
|
| - /*
|
| - * BIG NOTE: Now the ugly part. In previous versions
|
| - * of Libxslt (until 1.1.16), all the content of an
|
| - * extension instruction was processed and compiled without
|
| - * the need of the extension-author to explicitely call
|
| - * such a processing;.We now need to mimic this old
|
| - * behaviour in order to avoid breaking old code
|
| - * on the extension-author's side.
|
| - * The mechanism:
|
| - * 1) If the author does *not* set the
|
| - * compile-time-flag @extContentHandled, then we'll
|
| - * parse the content assuming that it's a "template"
|
| - * (or "sequence constructor in XSLT 2.0 terms).
|
| - * NOTE: If the extension is registered at
|
| - * transformation-time only, then there's no way of
|
| - * knowing that content shall be valid, and we'll
|
| - * process the content the same way.
|
| - * 2) If the author *does* set the flag, then we'll assume
|
| - * that the author has handled the parsing him/herself
|
| - * (e.g. called xsltParseSequenceConstructor(), etc.
|
| - * explicitely in his/her code).
|
| - */
|
| - if ((cur->children != NULL) &&
|
| - (cctxt->inode->extContentHandled == 0))
|
| - {
|
| - /*
|
| - * Default parsing of the content using the
|
| - * sequence-constructor model.
|
| - */
|
| - xsltParseSequenceConstructor(cctxt, cur->children);
|
| - }
|
| - } else {
|
| - /*
|
| - * Literal result element
|
| - * ----------------------------------------------------
|
| - * Allowed XSLT attributes:
|
| - * xsl:extension-element-prefixes CDATA #IMPLIED
|
| - * xsl:exclude-result-prefixes CDATA #IMPLIED
|
| - * TODO: xsl:use-attribute-sets %qnames; #IMPLIED
|
| - * xsl:version NMTOKEN #IMPLIED
|
| - */
|
| - cur->psvi = NULL;
|
| - cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE;
|
| - if (cur->properties != NULL) {
|
| - xmlAttrPtr attr = cur->properties;
|
| - /*
|
| - * Attribute "xsl:exclude-result-prefixes".
|
| - */
|
| - cctxt->inode->exclResultNs =
|
| - xsltParseExclResultPrefixes(cctxt, cur,
|
| - cctxt->inode->exclResultNs,
|
| - XSLT_ELEMENT_CATEGORY_LRE);
|
| - /*
|
| - * Attribute "xsl:version".
|
| - */
|
| - xsltParseAttrXSLTVersion(cctxt, cur,
|
| - XSLT_ELEMENT_CATEGORY_LRE);
|
| - /*
|
| - * Report invalid XSLT attributes.
|
| - * For XSLT 1.0 only xsl:use-attribute-sets is allowed
|
| - * next to xsl:version, xsl:exclude-result-prefixes and
|
| - * xsl:extension-element-prefixes.
|
| - *
|
| - * Mark all XSLT attributes, in order to skip such
|
| - * attributes when instantiating the LRE.
|
| - */
|
| - do {
|
| - if ((attr->psvi != xsltXSLTAttrMarker) &&
|
| - IS_XSLT_ATTR_FAST(attr))
|
| - {
|
| - if (! xmlStrEqual(attr->name,
|
| - BAD_CAST "use-attribute-sets"))
|
| - {
|
| - xsltTransformError(NULL, cctxt->style,
|
| - cur,
|
| - "Unknown XSLT attribute '%s'.\n",
|
| - attr->name);
|
| - cctxt->style->errors++;
|
| - } else {
|
| - /*
|
| - * XSLT attr marker.
|
| - */
|
| - attr->psvi = (void *) xsltXSLTAttrMarker;
|
| - }
|
| - }
|
| - attr = attr->next;
|
| - } while (attr != NULL);
|
| - }
|
| - /*
|
| - * Create/reuse info for the literal result element.
|
| - */
|
| - if (cctxt->inode->nsChanged)
|
| - xsltLREInfoCreate(cctxt, cur, 1);
|
| - cur->psvi = cctxt->inode->litResElemInfo;
|
| - /*
|
| - * Apply ns-aliasing on the element and on its attributes.
|
| - */
|
| - if (cctxt->hasNsAliases)
|
| - xsltLREBuildEffectiveNs(cctxt, cur);
|
| - /*
|
| - * Compile attribute value templates (AVT).
|
| - */
|
| - if (cur->properties) {
|
| - xmlAttrPtr attr = cur->properties;
|
| -
|
| - while (attr != NULL) {
|
| - xsltCompileAttr(cctxt->style, attr);
|
| - attr = attr->next;
|
| - }
|
| - }
|
| - /*
|
| - * Parse the content, which is defined to be a "template"
|
| - * (or "sequence constructor" in XSLT 2.0 terms).
|
| - */
|
| - if (cur->children != NULL) {
|
| - xsltParseSequenceConstructor(cctxt, cur->children);
|
| - }
|
| - }
|
| - /*
|
| - * Leave the non-XSLT element.
|
| - */
|
| - xsltCompilerNodePop(cctxt, cur);
|
| - }
|
| - }
|
| - cur = cur->next;
|
| - }
|
| - if (deleteNode != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_BLANKS
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseSequenceConstructor: removing xsl:text element\n");
|
| -#endif
|
| - xmlUnlinkNode(deleteNode);
|
| - xmlFreeNode(deleteNode);
|
| - deleteNode = NULL;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * xsltParseTemplateContent:
|
| - * @style: the XSLT stylesheet
|
| - * @templ: the node containing the content to be parsed
|
| - *
|
| - * Parses and compiles the content-model of an xsl:template element.
|
| - * Note that this is *not* the "template" content model (or "sequence
|
| - * constructor" in XSLT 2.0); it it allows addional xsl:param
|
| - * elements as immediate children of @templ.
|
| - *
|
| - * Called by:
|
| - * exsltFuncFunctionComp() (EXSLT, functions.c)
|
| - * So this is intended to be called from extension functions.
|
| - */
|
| -void
|
| -xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
|
| - if ((style == NULL) || (templ == NULL) ||
|
| - (templ->type == XML_NAMESPACE_DECL))
|
| - return;
|
| -
|
| - /*
|
| - * Detection of handled content of extension instructions.
|
| - */
|
| - if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) {
|
| - XSLT_CCTXT(style)->inode->extContentHandled = 1;
|
| - }
|
| -
|
| - if (templ->children != NULL) {
|
| - xmlNodePtr child = templ->children;
|
| - /*
|
| - * Process xsl:param elements, which can only occur as the
|
| - * immediate children of xsl:template (well, and of any
|
| - * user-defined extension instruction if needed).
|
| - */
|
| - do {
|
| - if ((child->type == XML_ELEMENT_NODE) &&
|
| - IS_XSLT_ELEM_FAST(child) &&
|
| - IS_XSLT_NAME(child, "param"))
|
| - {
|
| - XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM;
|
| - xsltParseAnyXSLTElem(XSLT_CCTXT(style), child);
|
| - } else
|
| - break;
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - /*
|
| - * Parse the content and register the pattern.
|
| - */
|
| - xsltParseSequenceConstructor(XSLT_CCTXT(style), child);
|
| - }
|
| -}
|
| -
|
| -#else /* XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseTemplateContent:
|
| - * @style: the XSLT stylesheet
|
| - * @templ: the container node (can be a document for literal results)
|
| - *
|
| - * parse a template content-model
|
| - * Clean-up the template content from unwanted ignorable blank nodes
|
| - * and process xslt:text
|
| - */
|
| -void
|
| -xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) {
|
| - xmlNodePtr cur, delete;
|
| -
|
| - if ((style == NULL) || (templ == NULL) ||
|
| - (templ->type == XML_NAMESPACE_DECL)) return;
|
| -
|
| - /*
|
| - * This content comes from the stylesheet
|
| - * For stylesheets, the set of whitespace-preserving
|
| - * element names consists of just xsl:text.
|
| - */
|
| - cur = templ->children;
|
| - delete = NULL;
|
| - while (cur != NULL) {
|
| - if (delete != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_BLANKS
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseTemplateContent: removing text\n");
|
| -#endif
|
| - xmlUnlinkNode(delete);
|
| - xmlFreeNode(delete);
|
| - delete = NULL;
|
| - }
|
| - if (IS_XSLT_ELEM(cur)) {
|
| - xsltStylePreCompute(style, cur);
|
| -
|
| - if (IS_XSLT_NAME(cur, "text")) {
|
| - /*
|
| - * TODO: Processing of xsl:text should be moved to
|
| - * xsltPreprocessStylesheet(), since otherwise this
|
| - * will be performed for every multiply included
|
| - * stylesheet; i.e. this here is not skipped with
|
| - * the use of the style->nopreproc flag.
|
| - */
|
| - if (cur->children != NULL) {
|
| - xmlChar *prop;
|
| - xmlNodePtr text = cur->children, next;
|
| - int noesc = 0;
|
| -
|
| - prop = xmlGetNsProp(cur,
|
| - (const xmlChar *)"disable-output-escaping",
|
| - NULL);
|
| - if (prop != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "Disable escaping: %s\n", text->content);
|
| -#endif
|
| - if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
|
| - noesc = 1;
|
| - } else if (!xmlStrEqual(prop,
|
| - (const xmlChar *)"no")){
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsl:text: disable-output-escaping allows only yes or no\n");
|
| - style->warnings++;
|
| -
|
| - }
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - while (text != NULL) {
|
| - if (text->type == XML_COMMENT_NODE) {
|
| - text = text->next;
|
| - continue;
|
| - }
|
| - if ((text->type != XML_TEXT_NODE) &&
|
| - (text->type != XML_CDATA_SECTION_NODE)) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseTemplateContent: xslt:text content problem\n");
|
| - style->errors++;
|
| - break;
|
| - }
|
| - if ((noesc) && (text->type != XML_CDATA_SECTION_NODE))
|
| - text->name = xmlStringTextNoenc;
|
| - text = text->next;
|
| - }
|
| -
|
| - /*
|
| - * replace xsl:text by the list of childs
|
| - */
|
| - if (text == NULL) {
|
| - text = cur->children;
|
| - while (text != NULL) {
|
| - if ((style->internalized) &&
|
| - (text->content != NULL) &&
|
| - (!xmlDictOwns(style->dict, text->content))) {
|
| -
|
| - /*
|
| - * internalize the text string
|
| - */
|
| - if (text->doc->dict != NULL) {
|
| - const xmlChar *tmp;
|
| -
|
| - tmp = xmlDictLookup(text->doc->dict,
|
| - text->content, -1);
|
| - if (tmp != text->content) {
|
| - xmlNodeSetContent(text, NULL);
|
| - text->content = (xmlChar *) tmp;
|
| - }
|
| - }
|
| - }
|
| -
|
| - next = text->next;
|
| - xmlUnlinkNode(text);
|
| - xmlAddPrevSibling(cur, text);
|
| - text = next;
|
| - }
|
| - }
|
| - }
|
| - delete = cur;
|
| - goto skip_children;
|
| - }
|
| - }
|
| - else if ((cur->ns != NULL) && (style->nsDefs != NULL) &&
|
| - (xsltCheckExtPrefix(style, cur->ns->prefix)))
|
| - {
|
| - /*
|
| - * okay this is an extension element compile it too
|
| - */
|
| - xsltStylePreCompute(style, cur);
|
| - }
|
| - else if (cur->type == XML_ELEMENT_NODE)
|
| - {
|
| - /*
|
| - * This is an element which will be output as part of the
|
| - * template exectution, precompile AVT if found.
|
| - */
|
| - if ((cur->ns == NULL) && (style->defaultAlias != NULL)) {
|
| - cur->ns = xmlSearchNsByHref(cur->doc, cur,
|
| - style->defaultAlias);
|
| - }
|
| - if (cur->properties != NULL) {
|
| - xmlAttrPtr attr = cur->properties;
|
| -
|
| - while (attr != NULL) {
|
| - xsltCompileAttr(style, attr);
|
| - attr = attr->next;
|
| - }
|
| - }
|
| - }
|
| - /*
|
| - * Skip to next node
|
| - */
|
| - if (cur->children != NULL) {
|
| - if (cur->children->type != XML_ENTITY_DECL) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - }
|
| -skip_children:
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| -
|
| - do {
|
| - cur = cur->parent;
|
| - if (cur == NULL)
|
| - break;
|
| - if (cur == templ) {
|
| - cur = NULL;
|
| - break;
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - break;
|
| - }
|
| - } while (cur != NULL);
|
| - }
|
| - if (delete != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseTemplateContent: removing text\n");
|
| -#endif
|
| - xmlUnlinkNode(delete);
|
| - xmlFreeNode(delete);
|
| - delete = NULL;
|
| - }
|
| -
|
| - /*
|
| - * Skip the first params
|
| - */
|
| - cur = templ->children;
|
| - while (cur != NULL) {
|
| - if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param"))))
|
| - break;
|
| - cur = cur->next;
|
| - }
|
| -
|
| - /*
|
| - * Browse the remainder of the template
|
| - */
|
| - while (cur != NULL) {
|
| - if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) {
|
| - xmlNodePtr param = cur;
|
| -
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseTemplateContent: ignoring misplaced param element\n");
|
| - if (style != NULL) style->warnings++;
|
| - cur = cur->next;
|
| - xmlUnlinkNode(param);
|
| - xmlFreeNode(param);
|
| - } else
|
| - break;
|
| - }
|
| -}
|
| -
|
| -#endif /* else XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetKey:
|
| - * @style: the XSLT stylesheet
|
| - * @key: the "key" element
|
| - *
|
| - * <!-- Category: top-level-element -->
|
| - * <xsl:key name = qname, match = pattern, use = expression />
|
| - *
|
| - * parse an XSLT stylesheet key definition and register it
|
| - */
|
| -
|
| -static void
|
| -xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) {
|
| - xmlChar *prop = NULL;
|
| - xmlChar *use = NULL;
|
| - xmlChar *match = NULL;
|
| - xmlChar *name = NULL;
|
| - xmlChar *nameURI = NULL;
|
| -
|
| - if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - /*
|
| - * Get arguments
|
| - */
|
| - prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(key, &prop);
|
| - if (prop == NULL) {
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - } else {
|
| - name = prop;
|
| - if (URI != NULL)
|
| - nameURI = xmlStrdup(URI);
|
| - }
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetKey: name %s\n", name);
|
| -#endif
|
| - } else {
|
| - xsltTransformError(NULL, style, key,
|
| - "xsl:key : error missing name\n");
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| -
|
| - match = xmlGetNsProp(key, (const xmlChar *)"match", NULL);
|
| - if (match == NULL) {
|
| - xsltTransformError(NULL, style, key,
|
| - "xsl:key : error missing match\n");
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| -
|
| - use = xmlGetNsProp(key, (const xmlChar *)"use", NULL);
|
| - if (use == NULL) {
|
| - xsltTransformError(NULL, style, key,
|
| - "xsl:key : error missing use\n");
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| -
|
| - /*
|
| - * register the keys
|
| - */
|
| - xsltAddKey(style, name, nameURI, match, use, key);
|
| -
|
| -
|
| -error:
|
| - if (use != NULL)
|
| - xmlFree(use);
|
| - if (match != NULL)
|
| - xmlFree(match);
|
| - if (name != NULL)
|
| - xmlFree(name);
|
| - if (nameURI != NULL)
|
| - xmlFree(nameURI);
|
| -
|
| - if (key->children != NULL) {
|
| - xsltParseContentError(style, key->children);
|
| - }
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -/**
|
| - * xsltParseXSLTTemplate:
|
| - * @style: the XSLT stylesheet
|
| - * @template: the "template" element
|
| - *
|
| - * parse an XSLT stylesheet template building the associated structures
|
| - * TODO: Is @style ever expected to be NULL?
|
| - *
|
| - * Called from:
|
| - * xsltParseXSLTStylesheet()
|
| - * xsltParseStylesheetTop()
|
| - */
|
| -
|
| -static void
|
| -xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) {
|
| - xsltTemplatePtr templ;
|
| - xmlChar *prop;
|
| - double priority;
|
| -
|
| - if ((cctxt == NULL) || (templNode == NULL) ||
|
| - (templNode->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - /*
|
| - * Create and link the structure
|
| - */
|
| - templ = xsltNewTemplate();
|
| - if (templ == NULL)
|
| - return;
|
| -
|
| - xsltCompilerNodePush(cctxt, templNode);
|
| - if (templNode->nsDef != NULL)
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, templNode);
|
| -
|
| - templ->next = cctxt->style->templates;
|
| - cctxt->style->templates = templ;
|
| - templ->style = cctxt->style;
|
| -
|
| - /*
|
| - * Attribute "mode".
|
| - */
|
| - prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *modeURI;
|
| -
|
| - /*
|
| - * TODO: We need a standardized function for extraction
|
| - * of namespace names and local names from QNames.
|
| - * Don't use xsltGetQNameURI() as it cannot channe�
|
| - * reports through the context.
|
| - */
|
| - modeURI = xsltGetQNameURI(templNode, &prop);
|
| - if (prop == NULL) {
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1);
|
| - xmlFree(prop);
|
| - prop = NULL;
|
| - if (xmlValidateNCName(templ->mode, 0)) {
|
| - xsltTransformError(NULL, cctxt->style, templNode,
|
| - "xsl:template: Attribute 'mode': The local part '%s' "
|
| - "of the value is not a valid NCName.\n", templ->name);
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - if (modeURI != NULL)
|
| - templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1);
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseXSLTTemplate: mode %s\n", templ->mode);
|
| -#endif
|
| - }
|
| - /*
|
| - * Attribute "match".
|
| - */
|
| - prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL);
|
| - if (prop != NULL) {
|
| - templ->match = prop;
|
| - prop = NULL;
|
| - }
|
| - /*
|
| - * Attribute "priority".
|
| - */
|
| - prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL);
|
| - if (prop != NULL) {
|
| - priority = xmlXPathStringEvalNumber(prop);
|
| - templ->priority = (float) priority;
|
| - xmlFree(prop);
|
| - prop = NULL;
|
| - }
|
| - /*
|
| - * Attribute "name".
|
| - */
|
| - prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *nameURI;
|
| - xsltTemplatePtr curTempl;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - nameURI = xsltGetQNameURI(templNode, &prop);
|
| - if (prop == NULL) {
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - templ->name = xmlDictLookup(cctxt->style->dict, prop, -1);
|
| - xmlFree(prop);
|
| - prop = NULL;
|
| - if (xmlValidateNCName(templ->name, 0)) {
|
| - xsltTransformError(NULL, cctxt->style, templNode,
|
| - "xsl:template: Attribute 'name': The local part '%s' of "
|
| - "the value is not a valid NCName.\n", templ->name);
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - if (nameURI != NULL)
|
| - templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1);
|
| - curTempl = templ->next;
|
| - while (curTempl != NULL) {
|
| - if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) &&
|
| - xmlStrEqual(curTempl->nameURI, nameURI) ) ||
|
| - (nameURI == NULL && curTempl->nameURI == NULL &&
|
| - xmlStrEqual(curTempl->name, templ->name)))
|
| - {
|
| - xsltTransformError(NULL, cctxt->style, templNode,
|
| - "xsl:template: error duplicate name '%s'\n", templ->name);
|
| - cctxt->style->errors++;
|
| - goto error;
|
| - }
|
| - curTempl = curTempl->next;
|
| - }
|
| - }
|
| - if (templNode->children != NULL) {
|
| - xsltParseTemplateContent(cctxt->style, templNode);
|
| - /*
|
| - * MAYBE TODO: Custom behaviour: In order to stay compatible with
|
| - * Xalan and MSXML(.NET), we could allow whitespace
|
| - * to appear before an xml:param element; this whitespace
|
| - * will additionally become part of the "template".
|
| - * NOTE that this is totally deviates from the spec, but
|
| - * is the de facto behaviour of Xalan and MSXML(.NET).
|
| - * Personally I wouldn't allow this, since if we have:
|
| - * <xsl:template ...xml:space="preserve">
|
| - * <xsl:param name="foo"/>
|
| - * <xsl:param name="bar"/>
|
| - * <xsl:param name="zoo"/>
|
| - * ... the whitespace between every xsl:param would be
|
| - * added to the result tree.
|
| - */
|
| - }
|
| -
|
| - templ->elem = templNode;
|
| - templ->content = templNode->children;
|
| - xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI);
|
| -
|
| -error:
|
| - xsltCompilerNodePop(cctxt, templNode);
|
| - return;
|
| -}
|
| -
|
| -#else /* XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetTemplate:
|
| - * @style: the XSLT stylesheet
|
| - * @template: the "template" element
|
| - *
|
| - * parse an XSLT stylesheet template building the associated structures
|
| - */
|
| -
|
| -static void
|
| -xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) {
|
| - xsltTemplatePtr ret;
|
| - xmlChar *prop;
|
| - xmlChar *mode = NULL;
|
| - xmlChar *modeURI = NULL;
|
| - double priority;
|
| -
|
| - if ((style == NULL) || (template == NULL) ||
|
| - (template->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - /*
|
| - * Create and link the structure
|
| - */
|
| - ret = xsltNewTemplate();
|
| - if (ret == NULL)
|
| - return;
|
| - ret->next = style->templates;
|
| - style->templates = ret;
|
| - ret->style = style;
|
| -
|
| - /*
|
| - * Get inherited namespaces
|
| - */
|
| - /*
|
| - * TODO: Apply the optimized in-scope-namespace mechanism
|
| - * as for the other XSLT instructions.
|
| - */
|
| - xsltGetInheritedNsList(style, ret, template);
|
| -
|
| - /*
|
| - * Get arguments
|
| - */
|
| - prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(template, &prop);
|
| - if (prop == NULL) {
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - } else {
|
| - mode = prop;
|
| - if (URI != NULL)
|
| - modeURI = xmlStrdup(URI);
|
| - }
|
| - ret->mode = xmlDictLookup(style->dict, mode, -1);
|
| - ret->modeURI = xmlDictLookup(style->dict, modeURI, -1);
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetTemplate: mode %s\n", mode);
|
| -#endif
|
| - if (mode != NULL) xmlFree(mode);
|
| - if (modeURI != NULL) xmlFree(modeURI);
|
| - }
|
| - prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL);
|
| - if (prop != NULL) {
|
| - if (ret->match != NULL) xmlFree(ret->match);
|
| - ret->match = prop;
|
| - }
|
| -
|
| - prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL);
|
| - if (prop != NULL) {
|
| - priority = xmlXPathStringEvalNumber(prop);
|
| - ret->priority = (float) priority;
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL);
|
| - if (prop != NULL) {
|
| - const xmlChar *URI;
|
| -
|
| - /*
|
| - * TODO: Don't use xsltGetQNameURI().
|
| - */
|
| - URI = xsltGetQNameURI(template, &prop);
|
| - if (prop == NULL) {
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - } else {
|
| - if (xmlValidateNCName(prop,0)) {
|
| - xsltTransformError(NULL, style, template,
|
| - "xsl:template : error invalid name '%s'\n", prop);
|
| - if (style != NULL) style->errors++;
|
| - goto error;
|
| - }
|
| - ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1);
|
| - xmlFree(prop);
|
| - prop = NULL;
|
| - if (URI != NULL)
|
| - ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1);
|
| - else
|
| - ret->nameURI = NULL;
|
| - }
|
| - }
|
| -
|
| - /*
|
| - * parse the content and register the pattern
|
| - */
|
| - xsltParseTemplateContent(style, template);
|
| - ret->elem = template;
|
| - ret->content = template->children;
|
| - xsltAddTemplate(style, ret, ret->mode, ret->modeURI);
|
| -
|
| -error:
|
| - return;
|
| -}
|
| -
|
| -#endif /* else XSLT_REFACTORED */
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -
|
| -/**
|
| - * xsltIncludeComp:
|
| - * @cctxt: the compilation contenxt
|
| - * @node: the xsl:include node
|
| - *
|
| - * Process the xslt include node on the source node
|
| - */
|
| -static xsltStyleItemIncludePtr
|
| -xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) {
|
| - xsltStyleItemIncludePtr item;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
|
| - return(NULL);
|
| -
|
| - node->psvi = NULL;
|
| - item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude));
|
| - if (item == NULL) {
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "xsltIncludeComp : malloc failed\n");
|
| - cctxt->style->errors++;
|
| - return(NULL);
|
| - }
|
| - memset(item, 0, sizeof(xsltStyleItemInclude));
|
| -
|
| - node->psvi = item;
|
| - item->inst = node;
|
| - item->type = XSLT_FUNC_INCLUDE;
|
| -
|
| - item->next = cctxt->style->preComps;
|
| - cctxt->style->preComps = (xsltElemPreCompPtr) item;
|
| -
|
| - return(item);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseFindTopLevelElem:
|
| - */
|
| -static int
|
| -xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr cur,
|
| - const xmlChar *name,
|
| - const xmlChar *namespaceURI,
|
| - int breakOnOtherElem,
|
| - xmlNodePtr *resultNode)
|
| -{
|
| - if (name == NULL)
|
| - return(-1);
|
| -
|
| - *resultNode = NULL;
|
| - while (cur != NULL) {
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - if ((cur->ns != NULL) && (cur->name != NULL)) {
|
| - if ((*(cur->name) == *name) &&
|
| - xmlStrEqual(cur->name, name) &&
|
| - xmlStrEqual(cur->ns->href, namespaceURI))
|
| - {
|
| - *resultNode = cur;
|
| - return(1);
|
| - }
|
| - }
|
| - if (breakOnOtherElem)
|
| - break;
|
| - }
|
| - cur = cur->next;
|
| - }
|
| - *resultNode = cur;
|
| - return(0);
|
| -}
|
| -
|
| -static int
|
| -xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt,
|
| - xmlNodePtr node,
|
| - xsltStyleType type)
|
| -{
|
| - int ret = 0;
|
| -
|
| - /*
|
| - * TODO: The reason why this function exists:
|
| - * due to historical reasons some of the
|
| - * top-level declarations are processed by functions
|
| - * in other files. Since we need still to set
|
| - * up the node-info and generate information like
|
| - * in-scope namespaces, this is a wrapper around
|
| - * those old parsing functions.
|
| - */
|
| - xsltCompilerNodePush(cctxt, node);
|
| - if (node->nsDef != NULL)
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, node);
|
| - cctxt->inode->type = type;
|
| -
|
| - switch (type) {
|
| - case XSLT_FUNC_INCLUDE:
|
| - {
|
| - int oldIsInclude;
|
| -
|
| - if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL)
|
| - goto exit;
|
| - /*
|
| - * Mark this stylesheet tree as being currently included.
|
| - */
|
| - oldIsInclude = cctxt->isInclude;
|
| - cctxt->isInclude = 1;
|
| -
|
| - if (xsltParseStylesheetInclude(cctxt->style, node) != 0) {
|
| - cctxt->style->errors++;
|
| - }
|
| - cctxt->isInclude = oldIsInclude;
|
| - }
|
| - break;
|
| - case XSLT_FUNC_PARAM:
|
| - xsltStylePreCompute(cctxt->style, node);
|
| - xsltParseGlobalParam(cctxt->style, node);
|
| - break;
|
| - case XSLT_FUNC_VARIABLE:
|
| - xsltStylePreCompute(cctxt->style, node);
|
| - xsltParseGlobalVariable(cctxt->style, node);
|
| - break;
|
| - case XSLT_FUNC_ATTRSET:
|
| - xsltParseStylesheetAttributeSet(cctxt->style, node);
|
| - break;
|
| - default:
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "Internal error: (xsltParseTopLevelXSLTElem) "
|
| - "Cannot handle this top-level declaration.\n");
|
| - cctxt->style->errors++;
|
| - ret = -1;
|
| - }
|
| -
|
| -exit:
|
| - xsltCompilerNodePop(cctxt, node);
|
| -
|
| - return(ret);
|
| -}
|
| -
|
| -#if 0
|
| -static int
|
| -xsltParseRemoveWhitespace(xmlNodePtr node)
|
| -{
|
| - if ((node == NULL) || (node->children == NULL))
|
| - return(0);
|
| - else {
|
| - xmlNodePtr delNode = NULL, child = node->children;
|
| -
|
| - do {
|
| - if (delNode) {
|
| - xmlUnlinkNode(delNode);
|
| - xmlFreeNode(delNode);
|
| - delNode = NULL;
|
| - }
|
| - if (((child->type == XML_TEXT_NODE) ||
|
| - (child->type == XML_CDATA_SECTION_NODE)) &&
|
| - (IS_BLANK_NODE(child)))
|
| - delNode = child;
|
| - child = child->next;
|
| - } while (child != NULL);
|
| - if (delNode) {
|
| - xmlUnlinkNode(delNode);
|
| - xmlFreeNode(delNode);
|
| - delNode = NULL;
|
| - }
|
| - }
|
| - return(0);
|
| -}
|
| -#endif
|
| -
|
| -static int
|
| -xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - int templates = 0;
|
| -#endif
|
| - xmlNodePtr cur, start = NULL;
|
| - xsltStylesheetPtr style;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL) ||
|
| - (node->type != XML_ELEMENT_NODE))
|
| - return(-1);
|
| -
|
| - style = cctxt->style;
|
| - /*
|
| - * At this stage all import declarations of all stylesheet modules
|
| - * with the same stylesheet level have been processed.
|
| - * Now we can safely parse the rest of the declarations.
|
| - */
|
| - if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include"))
|
| - {
|
| - xsltDocumentPtr include;
|
| - /*
|
| - * URGENT TODO: Make this work with simplified stylesheets!
|
| - * I.e., when we won't find an xsl:stylesheet element.
|
| - */
|
| - /*
|
| - * This is as include declaration.
|
| - */
|
| - include = ((xsltStyleItemIncludePtr) node->psvi)->include;
|
| - if (include == NULL) {
|
| - /* TODO: raise error? */
|
| - return(-1);
|
| - }
|
| - /*
|
| - * TODO: Actually an xsl:include should locate an embedded
|
| - * stylesheet as well; so the document-element won't always
|
| - * be the element where the actual stylesheet is rooted at.
|
| - * But such embedded stylesheets are not supported by Libxslt yet.
|
| - */
|
| - node = xmlDocGetRootElement(include->doc);
|
| - if (node == NULL) {
|
| - return(-1);
|
| - }
|
| - }
|
| -
|
| - if (node->children == NULL)
|
| - return(0);
|
| - /*
|
| - * Push the xsl:stylesheet/xsl:transform element.
|
| - */
|
| - xsltCompilerNodePush(cctxt, node);
|
| - cctxt->inode->isRoot = 1;
|
| - cctxt->inode->nsChanged = 0;
|
| - /*
|
| - * Start with the naked dummy info for literal result elements.
|
| - */
|
| - cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo;
|
| -
|
| - /*
|
| - * In every case, we need to have
|
| - * the in-scope namespaces of the element, where the
|
| - * stylesheet is rooted at, regardless if it's an XSLT
|
| - * instruction or a literal result instruction (or if
|
| - * this is an embedded stylesheet).
|
| - */
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, node);
|
| -
|
| - /*
|
| - * Process attributes of xsl:stylesheet/xsl:transform.
|
| - * --------------------------------------------------
|
| - * Allowed are:
|
| - * id = id
|
| - * extension-element-prefixes = tokens
|
| - * exclude-result-prefixes = tokens
|
| - * version = number (mandatory)
|
| - */
|
| - if (xsltParseAttrXSLTVersion(cctxt, node,
|
| - XSLT_ELEMENT_CATEGORY_XSLT) == 0)
|
| - {
|
| - /*
|
| - * Attribute "version".
|
| - * XSLT 1.0: "An xsl:stylesheet element *must* have a version
|
| - * attribute, indicating the version of XSLT that the
|
| - * stylesheet requires".
|
| - * The root element of a simplified stylesheet must also have
|
| - * this attribute.
|
| - */
|
| -#ifdef XSLT_REFACTORED_MANDATORY_VERSION
|
| - if (isXsltElem)
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "The attribute 'version' is missing.\n");
|
| - cctxt->style->errors++;
|
| -#else
|
| - /* OLD behaviour. */
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "xsl:version is missing: document may not be a stylesheet\n");
|
| - cctxt->style->warnings++;
|
| -#endif
|
| - }
|
| - /*
|
| - * The namespaces declared by the attributes
|
| - * "extension-element-prefixes" and
|
| - * "exclude-result-prefixes" are local to *this*
|
| - * stylesheet tree; i.e., they are *not* visible to
|
| - * other stylesheet-modules, whether imported or included.
|
| - *
|
| - * Attribute "extension-element-prefixes".
|
| - */
|
| - cctxt->inode->extElemNs =
|
| - xsltParseExtElemPrefixes(cctxt, node, NULL,
|
| - XSLT_ELEMENT_CATEGORY_XSLT);
|
| - /*
|
| - * Attribute "exclude-result-prefixes".
|
| - */
|
| - cctxt->inode->exclResultNs =
|
| - xsltParseExclResultPrefixes(cctxt, node, NULL,
|
| - XSLT_ELEMENT_CATEGORY_XSLT);
|
| - /*
|
| - * Create/reuse info for the literal result element.
|
| - */
|
| - if (cctxt->inode->nsChanged)
|
| - xsltLREInfoCreate(cctxt, node, 0);
|
| - /*
|
| - * Processed top-level elements:
|
| - * ----------------------------
|
| - * xsl:variable, xsl:param (QName, in-scope ns,
|
| - * expression (vars allowed))
|
| - * xsl:attribute-set (QName, in-scope ns)
|
| - * xsl:strip-space, xsl:preserve-space (XPath NameTests,
|
| - * in-scope ns)
|
| - * I *think* global scope, merge with includes
|
| - * xsl:output (QName, in-scope ns)
|
| - * xsl:key (QName, in-scope ns, pattern,
|
| - * expression (vars *not* allowed))
|
| - * xsl:decimal-format (QName, needs in-scope ns)
|
| - * xsl:namespace-alias (in-scope ns)
|
| - * global scope, merge with includes
|
| - * xsl:template (last, QName, pattern)
|
| - *
|
| - * (whitespace-only text-nodes have *not* been removed
|
| - * yet; this will be done in xsltParseSequenceConstructor)
|
| - *
|
| - * Report misplaced child-nodes first.
|
| - */
|
| - cur = node->children;
|
| - while (cur != NULL) {
|
| - if (cur->type == XML_TEXT_NODE) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Misplaced text node (content: '%s').\n",
|
| - (cur->content != NULL) ? cur->content : BAD_CAST "");
|
| - style->errors++;
|
| - } else if (cur->type != XML_ELEMENT_NODE) {
|
| - xsltTransformError(NULL, style, cur, "Misplaced node.\n");
|
| - style->errors++;
|
| - }
|
| - cur = cur->next;
|
| - }
|
| - /*
|
| - * Skip xsl:import elements; they have been processed
|
| - * already.
|
| - */
|
| - cur = node->children;
|
| - while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
|
| - cur = cur->next;
|
| - if (cur == NULL)
|
| - goto exit;
|
| -
|
| - start = cur;
|
| - /*
|
| - * Process all top-level xsl:param elements.
|
| - */
|
| - while ((cur != NULL) &&
|
| - xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1)
|
| - {
|
| - xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM);
|
| - cur = cur->next;
|
| - }
|
| - /*
|
| - * Process all top-level xsl:variable elements.
|
| - */
|
| - cur = start;
|
| - while ((cur != NULL) &&
|
| - xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1)
|
| - {
|
| - xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE);
|
| - cur = cur->next;
|
| - }
|
| - /*
|
| - * Process all the rest of top-level elements.
|
| - */
|
| - cur = start;
|
| - while (cur != NULL) {
|
| - /*
|
| - * Process element nodes.
|
| - */
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - if (cur->ns == NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Unexpected top-level element in no namespace.\n");
|
| - style->errors++;
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - /*
|
| - * Process all XSLT elements.
|
| - */
|
| - if (IS_XSLT_ELEM_FAST(cur)) {
|
| - /*
|
| - * xsl:import is only allowed at the beginning.
|
| - */
|
| - if (IS_XSLT_NAME(cur, "import")) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Misplaced xsl:import element.\n");
|
| - style->errors++;
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - /*
|
| - * TODO: Change the return type of the parsing functions
|
| - * to int.
|
| - */
|
| - if (IS_XSLT_NAME(cur, "template")) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - templates++;
|
| -#endif
|
| - /*
|
| - * TODO: Is the position of xsl:template in the
|
| - * tree significant? If not it would be easier to
|
| - * parse them at a later stage.
|
| - */
|
| - xsltParseXSLTTemplate(cctxt, cur);
|
| - } else if (IS_XSLT_NAME(cur, "variable")) {
|
| - /* NOP; done already */
|
| - } else if (IS_XSLT_NAME(cur, "param")) {
|
| - /* NOP; done already */
|
| - } else if (IS_XSLT_NAME(cur, "include")) {
|
| - if (cur->psvi != NULL)
|
| - xsltParseXSLTStylesheetElemCore(cctxt, cur);
|
| - else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Internal error: "
|
| - "(xsltParseXSLTStylesheetElemCore) "
|
| - "The xsl:include element was not compiled.\n");
|
| - style->errors++;
|
| - }
|
| - } else if (IS_XSLT_NAME(cur, "strip-space")) {
|
| - /* No node info needed. */
|
| - xsltParseStylesheetStripSpace(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "preserve-space")) {
|
| - /* No node info needed. */
|
| - xsltParseStylesheetPreserveSpace(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "output")) {
|
| - /* No node-info needed. */
|
| - xsltParseStylesheetOutput(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "key")) {
|
| - /* TODO: node-info needed for expressions ? */
|
| - xsltParseStylesheetKey(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "decimal-format")) {
|
| - /* No node-info needed. */
|
| - xsltParseStylesheetDecimalFormat(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "attribute-set")) {
|
| - xsltParseTopLevelXSLTElem(cctxt, cur,
|
| - XSLT_FUNC_ATTRSET);
|
| - } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
|
| - /* NOP; done already */
|
| - } else {
|
| - if (cctxt->inode->forwardsCompat) {
|
| - /*
|
| - * Forwards-compatible mode:
|
| - *
|
| - * XSLT-1: "if it is a top-level element and
|
| - * XSLT 1.0 does not allow such elements as top-level
|
| - * elements, then the element must be ignored along
|
| - * with its content;"
|
| - */
|
| - /*
|
| - * TODO: I don't think we should generate a warning.
|
| - */
|
| - xsltTransformError(NULL, style, cur,
|
| - "Forwards-compatible mode: Ignoring unknown XSLT "
|
| - "element '%s'.\n", cur->name);
|
| - style->warnings++;
|
| - } else {
|
| - xsltTransformError(NULL, style, cur,
|
| - "Unknown XSLT element '%s'.\n", cur->name);
|
| - style->errors++;
|
| - }
|
| - }
|
| - } else {
|
| - xsltTopLevelFunction function;
|
| -
|
| - /*
|
| - * Process non-XSLT elements, which are in a
|
| - * non-NULL namespace.
|
| - */
|
| - /*
|
| - * QUESTION: What does xsltExtModuleTopLevelLookup()
|
| - * do exactly?
|
| - */
|
| - function = xsltExtModuleTopLevelLookup(cur->name,
|
| - cur->ns->href);
|
| - if (function != NULL)
|
| - function(style, cur);
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseXSLTStylesheetElemCore : User-defined "
|
| - "data element '%s'.\n", cur->name);
|
| -#endif
|
| - }
|
| - }
|
| - cur = cur->next;
|
| - }
|
| -
|
| -exit:
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### END of parsing top-level elements of doc '%s'.\n",
|
| - node->doc->URL);
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### Templates: %d\n", templates);
|
| -#ifdef XSLT_REFACTORED
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### Max inodes: %d\n", cctxt->maxNodeInfos);
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "### Max LREs : %d\n", cctxt->maxLREs);
|
| -#endif /* XSLT_REFACTORED */
|
| -#endif /* WITH_XSLT_DEBUG_PARSING */
|
| -
|
| - xsltCompilerNodePop(cctxt, node);
|
| - return(0);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseXSLTStylesheet:
|
| - * @cctxt: the compiler context
|
| - * @node: the xsl:stylesheet/xsl:transform element-node
|
| - *
|
| - * Parses the xsl:stylesheet and xsl:transform element.
|
| - *
|
| - * <xsl:stylesheet
|
| - * id = id
|
| - * extension-element-prefixes = tokens
|
| - * exclude-result-prefixes = tokens
|
| - * version = number>
|
| - * <!-- Content: (xsl:import*, top-level-elements) -->
|
| - * </xsl:stylesheet>
|
| - *
|
| - * BIG TODO: The xsl:include stuff.
|
| - *
|
| - * Called by xsltParseStylesheetTree()
|
| - *
|
| - * Returns 0 on success, a positive result on errors and
|
| - * -1 on API or internal errors.
|
| - */
|
| -static int
|
| -xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
| -{
|
| - xmlNodePtr cur, start;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE))
|
| - return(-1);
|
| -
|
| - if (node->children == NULL)
|
| - goto exit;
|
| -
|
| - /*
|
| - * Process top-level elements:
|
| - * xsl:import (must be first)
|
| - * xsl:include (this is just a pre-processing)
|
| - */
|
| - cur = node->children;
|
| - /*
|
| - * Process xsl:import elements.
|
| - * XSLT 1.0: "The xsl:import element children must precede all
|
| - * other element children of an xsl:stylesheet element,
|
| - * including any xsl:include element children."
|
| - */
|
| - while ((cur != NULL) &&
|
| - xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1)
|
| - {
|
| - if (xsltParseStylesheetImport(cctxt->style, cur) != 0) {
|
| - cctxt->style->errors++;
|
| - }
|
| - cur = cur->next;
|
| - }
|
| - if (cur == NULL)
|
| - goto exit;
|
| - start = cur;
|
| - /*
|
| - * Pre-process all xsl:include elements.
|
| - */
|
| - cur = start;
|
| - while ((cur != NULL) &&
|
| - xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1)
|
| - {
|
| - xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE);
|
| - cur = cur->next;
|
| - }
|
| - /*
|
| - * Pre-process all xsl:namespace-alias elements.
|
| - * URGENT TODO: This won't work correctly: the order of included
|
| - * aliases and aliases defined here is significant.
|
| - */
|
| - cur = start;
|
| - while ((cur != NULL) &&
|
| - xsltParseFindTopLevelElem(cctxt, cur,
|
| - BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1)
|
| - {
|
| - xsltNamespaceAlias(cctxt->style, cur);
|
| - cur = cur->next;
|
| - }
|
| -
|
| - if (cctxt->isInclude) {
|
| - /*
|
| - * If this stylesheet is intended for inclusion, then
|
| - * we will process only imports and includes.
|
| - */
|
| - goto exit;
|
| - }
|
| - /*
|
| - * Now parse the rest of the top-level elements.
|
| - */
|
| - xsltParseXSLTStylesheetElemCore(cctxt, node);
|
| -exit:
|
| -
|
| - return(0);
|
| -}
|
| -
|
| -#else /* XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetTop:
|
| - * @style: the XSLT stylesheet
|
| - * @top: the top level "stylesheet" or "transform" element
|
| - *
|
| - * scan the top level elements of an XSL stylesheet
|
| - */
|
| -static void
|
| -xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
|
| - xmlNodePtr cur;
|
| - xmlChar *prop;
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - int templates = 0;
|
| -#endif
|
| -
|
| - if ((top == NULL) || (top->type != XML_ELEMENT_NODE))
|
| - return;
|
| -
|
| - prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL);
|
| - if (prop == NULL) {
|
| - xsltTransformError(NULL, style, top,
|
| - "xsl:version is missing: document may not be a stylesheet\n");
|
| - if (style != NULL) style->warnings++;
|
| - } else {
|
| - if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
|
| - (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
|
| - xsltTransformError(NULL, style, top,
|
| - "xsl:version: only 1.1 features are supported\n");
|
| - if (style != NULL) {
|
| - style->forwards_compatible = 1;
|
| - style->warnings++;
|
| - }
|
| - }
|
| - xmlFree(prop);
|
| - }
|
| -
|
| - /*
|
| - * process xsl:import elements
|
| - */
|
| - cur = top->children;
|
| - while (cur != NULL) {
|
| - if (IS_BLANK_NODE(cur)) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) {
|
| - if (xsltParseStylesheetImport(style, cur) != 0)
|
| - if (style != NULL) style->errors++;
|
| - } else
|
| - break;
|
| - cur = cur->next;
|
| - }
|
| -
|
| - /*
|
| - * process other top-level elements
|
| - */
|
| - while (cur != NULL) {
|
| - if (IS_BLANK_NODE(cur)) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - if (cur->type == XML_TEXT_NODE) {
|
| - if (cur->content != NULL) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "misplaced text node: '%s'\n", cur->content);
|
| - }
|
| - if (style != NULL) style->errors++;
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) {
|
| - xsltGenericError(xsltGenericErrorContext,
|
| - "Found a top-level element %s with null namespace URI\n",
|
| - cur->name);
|
| - if (style != NULL) style->errors++;
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) {
|
| - xsltTopLevelFunction function;
|
| -
|
| - function = xsltExtModuleTopLevelLookup(cur->name,
|
| - cur->ns->href);
|
| - if (function != NULL)
|
| - function(style, cur);
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetTop : found foreign element %s\n",
|
| - cur->name);
|
| -#endif
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - if (IS_XSLT_NAME(cur, "import")) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylesheetTop: ignoring misplaced import element\n");
|
| - if (style != NULL) style->errors++;
|
| - } else if (IS_XSLT_NAME(cur, "include")) {
|
| - if (xsltParseStylesheetInclude(style, cur) != 0)
|
| - if (style != NULL) style->errors++;
|
| - } else if (IS_XSLT_NAME(cur, "strip-space")) {
|
| - xsltParseStylesheetStripSpace(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "preserve-space")) {
|
| - xsltParseStylesheetPreserveSpace(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "output")) {
|
| - xsltParseStylesheetOutput(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "key")) {
|
| - xsltParseStylesheetKey(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "decimal-format")) {
|
| - xsltParseStylesheetDecimalFormat(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "attribute-set")) {
|
| - xsltParseStylesheetAttributeSet(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "variable")) {
|
| - xsltParseGlobalVariable(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "param")) {
|
| - xsltParseGlobalParam(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "template")) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - templates++;
|
| -#endif
|
| - xsltParseStylesheetTemplate(style, cur);
|
| - } else if (IS_XSLT_NAME(cur, "namespace-alias")) {
|
| - xsltNamespaceAlias(style, cur);
|
| - } else {
|
| - if ((style != NULL) && (style->forwards_compatible == 0)) {
|
| - xsltTransformError(NULL, style, cur,
|
| - "xsltParseStylesheetTop: unknown %s element\n",
|
| - cur->name);
|
| - if (style != NULL) style->errors++;
|
| - }
|
| - }
|
| - cur = cur->next;
|
| - }
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "parsed %d templates\n", templates);
|
| -#endif
|
| -}
|
| -
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| -/**
|
| - * xsltParseSimplifiedStylesheetTree:
|
| - *
|
| - * @style: the stylesheet (TODO: Change this to the compiler context)
|
| - * @doc: the document containing the stylesheet.
|
| - * @node: the node where the stylesheet is rooted at
|
| - *
|
| - * Returns 0 in case of success, a positive result if an error occurred
|
| - * and -1 on API and internal errors.
|
| - */
|
| -static int
|
| -xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt,
|
| - xmlDocPtr doc,
|
| - xmlNodePtr node)
|
| -{
|
| - xsltTemplatePtr templ;
|
| -
|
| - if ((cctxt == NULL) || (node == NULL))
|
| - return(-1);
|
| -
|
| - if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE)
|
| - {
|
| - /*
|
| - * TODO: Adjust report, since this might be an
|
| - * embedded stylesheet.
|
| - */
|
| - xsltTransformError(NULL, cctxt->style, node,
|
| - "The attribute 'xsl:version' is missing; cannot identify "
|
| - "this document as an XSLT stylesheet document.\n");
|
| - cctxt->style->errors++;
|
| - return(1);
|
| - }
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseSimplifiedStylesheetTree: document is stylesheet\n");
|
| -#endif
|
| -
|
| - /*
|
| - * Create and link the template
|
| - */
|
| - templ = xsltNewTemplate();
|
| - if (templ == NULL) {
|
| - return(-1);
|
| - }
|
| - templ->next = cctxt->style->templates;
|
| - cctxt->style->templates = templ;
|
| - templ->match = xmlStrdup(BAD_CAST "/");
|
| -
|
| - /*
|
| - * Note that we push the document-node in this special case.
|
| - */
|
| - xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
|
| - /*
|
| - * In every case, we need to have
|
| - * the in-scope namespaces of the element, where the
|
| - * stylesheet is rooted at, regardless if it's an XSLT
|
| - * instruction or a literal result instruction (or if
|
| - * this is an embedded stylesheet).
|
| - */
|
| - cctxt->inode->inScopeNs =
|
| - xsltCompilerBuildInScopeNsList(cctxt, node);
|
| - /*
|
| - * Parse the content and register the match-pattern.
|
| - */
|
| - xsltParseSequenceConstructor(cctxt, node);
|
| - xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
|
| -
|
| - templ->elem = (xmlNodePtr) doc;
|
| - templ->content = node;
|
| - xsltAddTemplate(cctxt->style, templ, NULL, NULL);
|
| - cctxt->style->literal_result = 1;
|
| - return(0);
|
| -}
|
| -
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| -/**
|
| - * xsltRestoreDocumentNamespaces:
|
| - * @ns: map of namespaces
|
| - * @doc: the document
|
| - *
|
| - * Restore the namespaces for the document
|
| - *
|
| - * Returns 0 in case of success, -1 in case of failure
|
| - */
|
| -int
|
| -xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc)
|
| -{
|
| - if (doc == NULL)
|
| - return(-1);
|
| - /*
|
| - * Revert the changes we have applied to the namespace-URIs of
|
| - * ns-decls.
|
| - */
|
| - while (ns != NULL) {
|
| - if ((ns->doc == doc) && (ns->ns != NULL)) {
|
| - ns->ns->href = ns->origNsName;
|
| - ns->origNsName = NULL;
|
| - ns->ns = NULL;
|
| - }
|
| - ns = ns->next;
|
| - }
|
| - return(0);
|
| -}
|
| -#endif /* XSLT_REFACTORED_XSLT_NSCOMP */
|
| -
|
| -/**
|
| - * xsltParseStylesheetProcess:
|
| - * @style: the XSLT stylesheet (the current stylesheet-level)
|
| - * @doc: and xmlDoc parsed XML
|
| - *
|
| - * Parses an XSLT stylesheet, adding the associated structures.
|
| - * Called by:
|
| - * xsltParseStylesheetImportedDoc() (xslt.c)
|
| - * xsltParseStylesheetInclude() (imports.c)
|
| - *
|
| - * Returns the value of the @style parameter if everything
|
| - * went right, NULL if something went amiss.
|
| - */
|
| -xsltStylesheetPtr
|
| -xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc)
|
| -{
|
| - xsltCompilerCtxtPtr cctxt;
|
| - xmlNodePtr cur;
|
| - int oldIsSimplifiedStylesheet;
|
| -
|
| - xsltInitGlobals();
|
| -
|
| - if ((style == NULL) || (doc == NULL))
|
| - return(NULL);
|
| -
|
| - cctxt = XSLT_CCTXT(style);
|
| -
|
| - cur = xmlDocGetRootElement(doc);
|
| - if (cur == NULL) {
|
| - xsltTransformError(NULL, style, (xmlNodePtr) doc,
|
| - "xsltParseStylesheetProcess : empty stylesheet\n");
|
| - return(NULL);
|
| - }
|
| - oldIsSimplifiedStylesheet = cctxt->simplified;
|
| -
|
| - if ((IS_XSLT_ELEM(cur)) &&
|
| - ((IS_XSLT_NAME(cur, "stylesheet")) ||
|
| - (IS_XSLT_NAME(cur, "transform")))) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetProcess : found stylesheet\n");
|
| -#endif
|
| - cctxt->simplified = 0;
|
| - style->literal_result = 0;
|
| - } else {
|
| - cctxt->simplified = 1;
|
| - style->literal_result = 1;
|
| - }
|
| - /*
|
| - * Pre-process the stylesheet if not already done before.
|
| - * This will remove PIs and comments, merge adjacent
|
| - * text nodes, internalize strings, etc.
|
| - */
|
| - if (! style->nopreproc)
|
| - xsltParsePreprocessStylesheetTree(cctxt, cur);
|
| - /*
|
| - * Parse and compile the stylesheet.
|
| - */
|
| - if (style->literal_result == 0) {
|
| - if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0)
|
| - return(NULL);
|
| - } else {
|
| - if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0)
|
| - return(NULL);
|
| - }
|
| -
|
| - cctxt->simplified = oldIsSimplifiedStylesheet;
|
| -
|
| - return(style);
|
| -}
|
| -
|
| -#else /* XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetProcess:
|
| - * @ret: the XSLT stylesheet (the current stylesheet-level)
|
| - * @doc: and xmlDoc parsed XML
|
| - *
|
| - * Parses an XSLT stylesheet, adding the associated structures.
|
| - * Called by:
|
| - * xsltParseStylesheetImportedDoc() (xslt.c)
|
| - * xsltParseStylesheetInclude() (imports.c)
|
| - *
|
| - * Returns the value of the @style parameter if everything
|
| - * went right, NULL if something went amiss.
|
| - */
|
| -xsltStylesheetPtr
|
| -xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
|
| - xmlNodePtr cur;
|
| -
|
| - xsltInitGlobals();
|
| -
|
| - if (doc == NULL)
|
| - return(NULL);
|
| - if (ret == NULL)
|
| - return(ret);
|
| -
|
| - /*
|
| - * First steps, remove blank nodes,
|
| - * locate the xsl:stylesheet element and the
|
| - * namespace declaration.
|
| - */
|
| - cur = xmlDocGetRootElement(doc);
|
| - if (cur == NULL) {
|
| - xsltTransformError(NULL, ret, (xmlNodePtr) doc,
|
| - "xsltParseStylesheetProcess : empty stylesheet\n");
|
| - return(NULL);
|
| - }
|
| -
|
| - if ((IS_XSLT_ELEM(cur)) &&
|
| - ((IS_XSLT_NAME(cur, "stylesheet")) ||
|
| - (IS_XSLT_NAME(cur, "transform")))) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetProcess : found stylesheet\n");
|
| -#endif
|
| - ret->literal_result = 0;
|
| - xsltParseStylesheetExcludePrefix(ret, cur, 1);
|
| - xsltParseStylesheetExtPrefix(ret, cur, 1);
|
| - } else {
|
| - xsltParseStylesheetExcludePrefix(ret, cur, 0);
|
| - xsltParseStylesheetExtPrefix(ret, cur, 0);
|
| - ret->literal_result = 1;
|
| - }
|
| - if (!ret->nopreproc) {
|
| - xsltPreprocessStylesheet(ret, cur);
|
| - }
|
| - if (ret->literal_result == 0) {
|
| - xsltParseStylesheetTop(ret, cur);
|
| - } else {
|
| - xmlChar *prop;
|
| - xsltTemplatePtr template;
|
| -
|
| - /*
|
| - * the document itself might be the template, check xsl:version
|
| - */
|
| - prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE);
|
| - if (prop == NULL) {
|
| - xsltTransformError(NULL, ret, cur,
|
| - "xsltParseStylesheetProcess : document is not a stylesheet\n");
|
| - return(NULL);
|
| - }
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetProcess : document is stylesheet\n");
|
| -#endif
|
| -
|
| - if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) &&
|
| - (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) {
|
| - xsltTransformError(NULL, ret, cur,
|
| - "xsl:version: only 1.1 features are supported\n");
|
| - ret->forwards_compatible = 1;
|
| - ret->warnings++;
|
| - }
|
| - xmlFree(prop);
|
| -
|
| - /*
|
| - * Create and link the template
|
| - */
|
| - template = xsltNewTemplate();
|
| - if (template == NULL) {
|
| - return(NULL);
|
| - }
|
| - template->next = ret->templates;
|
| - ret->templates = template;
|
| - template->match = xmlStrdup((const xmlChar *)"/");
|
| -
|
| - /*
|
| - * parse the content and register the pattern
|
| - */
|
| - xsltParseTemplateContent(ret, (xmlNodePtr) doc);
|
| - template->elem = (xmlNodePtr) doc;
|
| - template->content = doc->children;
|
| - xsltAddTemplate(ret, template, NULL, NULL);
|
| - ret->literal_result = 1;
|
| - }
|
| -
|
| - return(ret);
|
| -}
|
| -
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| -/**
|
| - * xsltParseStylesheetImportedDoc:
|
| - * @doc: an xmlDoc parsed XML
|
| - * @parentStyle: pointer to the parent stylesheet (if it exists)
|
| - *
|
| - * parse an XSLT stylesheet building the associated structures
|
| - * except the processing not needed for imported documents.
|
| - *
|
| - * Returns a new XSLT stylesheet structure.
|
| - */
|
| -
|
| -xsltStylesheetPtr
|
| -xsltParseStylesheetImportedDoc(xmlDocPtr doc,
|
| - xsltStylesheetPtr parentStyle) {
|
| - xsltStylesheetPtr retStyle;
|
| -
|
| - if (doc == NULL)
|
| - return(NULL);
|
| -
|
| - retStyle = xsltNewStylesheet();
|
| - if (retStyle == NULL)
|
| - return(NULL);
|
| - /*
|
| - * Set the importing stylesheet module; also used to detect recursion.
|
| - */
|
| - retStyle->parent = parentStyle;
|
| - /*
|
| - * Adjust the string dict.
|
| - */
|
| - if (doc->dict != NULL) {
|
| - xmlDictFree(retStyle->dict);
|
| - retStyle->dict = doc->dict;
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "reusing dictionary from %s for stylesheet\n",
|
| - doc->URL);
|
| -#endif
|
| - xmlDictReference(retStyle->dict);
|
| - }
|
| -
|
| - /*
|
| - * TODO: Eliminate xsltGatherNamespaces(); we must not restrict
|
| - * the stylesheet to containt distinct namespace prefixes.
|
| - */
|
| - xsltGatherNamespaces(retStyle);
|
| -
|
| -#ifdef XSLT_REFACTORED
|
| - {
|
| - xsltCompilerCtxtPtr cctxt;
|
| - xsltStylesheetPtr oldCurSheet;
|
| -
|
| - if (parentStyle == NULL) {
|
| - xsltPrincipalStylesheetDataPtr principalData;
|
| - /*
|
| - * Principal stylesheet
|
| - * --------------------
|
| - */
|
| - retStyle->principal = retStyle;
|
| - /*
|
| - * Create extra data for the principal stylesheet.
|
| - */
|
| - principalData = xsltNewPrincipalStylesheetData();
|
| - if (principalData == NULL) {
|
| - xsltFreeStylesheet(retStyle);
|
| - return(NULL);
|
| - }
|
| - retStyle->principalData = principalData;
|
| - /*
|
| - * Create the compilation context
|
| - * ------------------------------
|
| - * (only once; for the principal stylesheet).
|
| - * This is currently the only function where the
|
| - * compilation context is created.
|
| - */
|
| - cctxt = xsltCompilationCtxtCreate(retStyle);
|
| - if (cctxt == NULL) {
|
| - xsltFreeStylesheet(retStyle);
|
| - return(NULL);
|
| - }
|
| - retStyle->compCtxt = (void *) cctxt;
|
| - cctxt->style = retStyle;
|
| - cctxt->dict = retStyle->dict;
|
| - cctxt->psData = principalData;
|
| - /*
|
| - * Push initial dummy node info.
|
| - */
|
| - cctxt->depth = -1;
|
| - xsltCompilerNodePush(cctxt, (xmlNodePtr) doc);
|
| - } else {
|
| - /*
|
| - * Imported stylesheet.
|
| - */
|
| - retStyle->principal = parentStyle->principal;
|
| - cctxt = parentStyle->compCtxt;
|
| - retStyle->compCtxt = cctxt;
|
| - }
|
| - /*
|
| - * Save the old and set the current stylesheet structure in the
|
| - * compilation context.
|
| - */
|
| - oldCurSheet = cctxt->style;
|
| - cctxt->style = retStyle;
|
| -
|
| - retStyle->doc = doc;
|
| - xsltParseStylesheetProcess(retStyle, doc);
|
| -
|
| - cctxt->style = oldCurSheet;
|
| - if (parentStyle == NULL) {
|
| - /*
|
| - * Pop the initial dummy node info.
|
| - */
|
| - xsltCompilerNodePop(cctxt, (xmlNodePtr) doc);
|
| - } else {
|
| - /*
|
| - * Clear the compilation context of imported
|
| - * stylesheets.
|
| - * TODO: really?
|
| - */
|
| - /* retStyle->compCtxt = NULL; */
|
| - }
|
| - /*
|
| - * Free the stylesheet if there were errors.
|
| - */
|
| - if (retStyle != NULL) {
|
| - if (retStyle->errors != 0) {
|
| -#ifdef XSLT_REFACTORED_XSLT_NSCOMP
|
| - /*
|
| - * Restore all changes made to namespace URIs of ns-decls.
|
| - */
|
| - if (cctxt->psData->nsMap)
|
| - xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc);
|
| -#endif
|
| - /*
|
| - * Detach the doc from the stylesheet; otherwise the doc
|
| - * will be freed in xsltFreeStylesheet().
|
| - */
|
| - retStyle->doc = NULL;
|
| - /*
|
| - * Cleanup the doc if its the main stylesheet.
|
| - */
|
| - if (parentStyle == NULL) {
|
| - xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc));
|
| - if (retStyle->compCtxt != NULL) {
|
| - xsltCompilationCtxtFree(retStyle->compCtxt);
|
| - retStyle->compCtxt = NULL;
|
| - }
|
| - }
|
| -
|
| - xsltFreeStylesheet(retStyle);
|
| - retStyle = NULL;
|
| - }
|
| - }
|
| - }
|
| -
|
| -#else /* XSLT_REFACTORED */
|
| - /*
|
| - * Old behaviour.
|
| - */
|
| - retStyle->doc = doc;
|
| - if (xsltParseStylesheetProcess(retStyle, doc) == NULL) {
|
| - retStyle->doc = NULL;
|
| - xsltFreeStylesheet(retStyle);
|
| - retStyle = NULL;
|
| - }
|
| - if (retStyle != NULL) {
|
| - if (retStyle->errors != 0) {
|
| - retStyle->doc = NULL;
|
| - if (parentStyle == NULL)
|
| - xsltCleanupStylesheetTree(doc,
|
| - xmlDocGetRootElement(doc));
|
| - xsltFreeStylesheet(retStyle);
|
| - retStyle = NULL;
|
| - }
|
| - }
|
| -#endif /* else of XSLT_REFACTORED */
|
| -
|
| - return(retStyle);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseStylesheetDoc:
|
| - * @doc: and xmlDoc parsed XML
|
| - *
|
| - * parse an XSLT stylesheet, building the associated structures. doc
|
| - * is kept as a reference within the returned stylesheet, so changes
|
| - * to doc after the parsing will be reflected when the stylesheet
|
| - * is applied, and the doc is automatically freed when the
|
| - * stylesheet is closed.
|
| - *
|
| - * Returns a new XSLT stylesheet structure.
|
| - */
|
| -
|
| -xsltStylesheetPtr
|
| -xsltParseStylesheetDoc(xmlDocPtr doc) {
|
| - xsltStylesheetPtr ret;
|
| -
|
| - xsltInitGlobals();
|
| -
|
| - ret = xsltParseStylesheetImportedDoc(doc, NULL);
|
| - if (ret == NULL)
|
| - return(NULL);
|
| -
|
| - xsltResolveStylesheetAttributeSet(ret);
|
| -#ifdef XSLT_REFACTORED
|
| - /*
|
| - * Free the compilation context.
|
| - * TODO: Check if it's better to move this cleanup to
|
| - * xsltParseStylesheetImportedDoc().
|
| - */
|
| - if (ret->compCtxt != NULL) {
|
| - xsltCompilationCtxtFree(XSLT_CCTXT(ret));
|
| - ret->compCtxt = NULL;
|
| - }
|
| -#endif
|
| - return(ret);
|
| -}
|
| -
|
| -/**
|
| - * xsltParseStylesheetFile:
|
| - * @filename: the filename/URL to the stylesheet
|
| - *
|
| - * Load and parse an XSLT stylesheet
|
| - *
|
| - * Returns a new XSLT stylesheet structure.
|
| - */
|
| -
|
| -xsltStylesheetPtr
|
| -xsltParseStylesheetFile(const xmlChar* filename) {
|
| - xsltSecurityPrefsPtr sec;
|
| - xsltStylesheetPtr ret;
|
| - xmlDocPtr doc;
|
| -
|
| - xsltInitGlobals();
|
| -
|
| - if (filename == NULL)
|
| - return(NULL);
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltParseStylesheetFile : parse %s\n", filename);
|
| -#endif
|
| -
|
| - /*
|
| - * Security framework check
|
| - */
|
| - sec = xsltGetDefaultSecurityPrefs();
|
| - if (sec != NULL) {
|
| - int res;
|
| -
|
| - res = xsltCheckRead(sec, NULL, filename);
|
| - if (res == 0) {
|
| - xsltTransformError(NULL, NULL, NULL,
|
| - "xsltParseStylesheetFile: read rights for %s denied\n",
|
| - filename);
|
| - return(NULL);
|
| - }
|
| - }
|
| -
|
| - doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS,
|
| - NULL, XSLT_LOAD_START);
|
| - if (doc == NULL) {
|
| - xsltTransformError(NULL, NULL, NULL,
|
| - "xsltParseStylesheetFile : cannot parse %s\n", filename);
|
| - return(NULL);
|
| - }
|
| - ret = xsltParseStylesheetDoc(doc);
|
| - if (ret == NULL) {
|
| - xmlFreeDoc(doc);
|
| - return(NULL);
|
| - }
|
| -
|
| - return(ret);
|
| -}
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Handling of Stylesheet PI *
|
| - * *
|
| - ************************************************************************/
|
| -
|
| -#define CUR (*cur)
|
| -#define SKIP(val) cur += (val)
|
| -#define NXT(val) cur[(val)]
|
| -#define SKIP_BLANKS \
|
| - while (IS_BLANK(CUR)) NEXT
|
| -#define NEXT ((*cur) ? cur++ : cur)
|
| -
|
| -/**
|
| - * xsltParseStylesheetPI:
|
| - * @value: the value of the PI
|
| - *
|
| - * This function checks that the type is text/xml and extracts
|
| - * the URI-Reference for the stylesheet
|
| - *
|
| - * Returns the URI-Reference for the stylesheet or NULL (it need to
|
| - * be freed by the caller)
|
| - */
|
| -static xmlChar *
|
| -xsltParseStylesheetPI(const xmlChar *value) {
|
| - const xmlChar *cur;
|
| - const xmlChar *start;
|
| - xmlChar *val;
|
| - xmlChar tmp;
|
| - xmlChar *href = NULL;
|
| - int isXml = 0;
|
| -
|
| - if (value == NULL)
|
| - return(NULL);
|
| -
|
| - cur = value;
|
| - while (CUR != 0) {
|
| - SKIP_BLANKS;
|
| - if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') &&
|
| - (NXT(3) == 'e')) {
|
| - SKIP(4);
|
| - SKIP_BLANKS;
|
| - if (CUR != '=')
|
| - continue;
|
| - NEXT;
|
| - if ((CUR != '\'') && (CUR != '"'))
|
| - continue;
|
| - tmp = CUR;
|
| - NEXT;
|
| - start = cur;
|
| - while ((CUR != 0) && (CUR != tmp))
|
| - NEXT;
|
| - if (CUR != tmp)
|
| - continue;
|
| - val = xmlStrndup(start, cur - start);
|
| - NEXT;
|
| - if (val == NULL)
|
| - return(NULL);
|
| - if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) &&
|
| - (xmlStrcasecmp(val, BAD_CAST "text/xsl"))) {
|
| - xmlFree(val);
|
| - break;
|
| - }
|
| - isXml = 1;
|
| - xmlFree(val);
|
| - } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') &&
|
| - (NXT(3) == 'f')) {
|
| - SKIP(4);
|
| - SKIP_BLANKS;
|
| - if (CUR != '=')
|
| - continue;
|
| - NEXT;
|
| - if ((CUR != '\'') && (CUR != '"'))
|
| - continue;
|
| - tmp = CUR;
|
| - NEXT;
|
| - start = cur;
|
| - while ((CUR != 0) && (CUR != tmp))
|
| - NEXT;
|
| - if (CUR != tmp)
|
| - continue;
|
| - if (href == NULL)
|
| - href = xmlStrndup(start, cur - start);
|
| - NEXT;
|
| - } else {
|
| - while ((CUR != 0) && (!IS_BLANK(CUR)))
|
| - NEXT;
|
| - }
|
| -
|
| - }
|
| -
|
| - if (!isXml) {
|
| - if (href != NULL)
|
| - xmlFree(href);
|
| - href = NULL;
|
| - }
|
| - return(href);
|
| -}
|
| -
|
| -/**
|
| - * xsltLoadStylesheetPI:
|
| - * @doc: a document to process
|
| - *
|
| - * This function tries to locate the stylesheet PI in the given document
|
| - * If found, and if contained within the document, it will extract
|
| - * that subtree to build the stylesheet to process @doc (doc itself will
|
| - * be modified). If found but referencing an external document it will
|
| - * attempt to load it and generate a stylesheet from it. In both cases,
|
| - * the resulting stylesheet and the document need to be freed once the
|
| - * transformation is done.
|
| - *
|
| - * Returns a new XSLT stylesheet structure or NULL if not found.
|
| - */
|
| -xsltStylesheetPtr
|
| -xsltLoadStylesheetPI(xmlDocPtr doc) {
|
| - xmlNodePtr child;
|
| - xsltStylesheetPtr ret = NULL;
|
| - xmlChar *href = NULL;
|
| - xmlURIPtr URI;
|
| -
|
| - xsltInitGlobals();
|
| -
|
| - if (doc == NULL)
|
| - return(NULL);
|
| -
|
| - /*
|
| - * Find the text/xml stylesheet PI id any before the root
|
| - */
|
| - child = doc->children;
|
| - while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) {
|
| - if ((child->type == XML_PI_NODE) &&
|
| - (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) {
|
| - href = xsltParseStylesheetPI(child->content);
|
| - if (href != NULL)
|
| - break;
|
| - }
|
| - child = child->next;
|
| - }
|
| -
|
| - /*
|
| - * If found check the href to select processing
|
| - */
|
| - if (href != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltLoadStylesheetPI : found PI href=%s\n", href);
|
| -#endif
|
| - URI = xmlParseURI((const char *) href);
|
| - if (URI == NULL) {
|
| - xsltTransformError(NULL, NULL, child,
|
| - "xml-stylesheet : href %s is not valid\n", href);
|
| - xmlFree(href);
|
| - return(NULL);
|
| - }
|
| - if ((URI->fragment != NULL) && (URI->scheme == NULL) &&
|
| - (URI->opaque == NULL) && (URI->authority == NULL) &&
|
| - (URI->server == NULL) && (URI->user == NULL) &&
|
| - (URI->path == NULL) && (URI->query == NULL)) {
|
| - xmlAttrPtr ID;
|
| -
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltLoadStylesheetPI : Reference to ID %s\n", href);
|
| -#endif
|
| - if (URI->fragment[0] == '#')
|
| - ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1]));
|
| - else
|
| - ID = xmlGetID(doc, (const xmlChar *) URI->fragment);
|
| - if (ID == NULL) {
|
| - xsltTransformError(NULL, NULL, child,
|
| - "xml-stylesheet : no ID %s found\n", URI->fragment);
|
| - } else {
|
| - xmlDocPtr fake;
|
| - xmlNodePtr subtree, newtree;
|
| - xmlNsPtr ns;
|
| -
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "creating new document from %s for embedded stylesheet\n",
|
| - doc->URL);
|
| -#endif
|
| - /*
|
| - * move the subtree in a new document passed to
|
| - * the stylesheet analyzer
|
| - */
|
| - subtree = ID->parent;
|
| - fake = xmlNewDoc(NULL);
|
| - if (fake != NULL) {
|
| - /*
|
| - * Should the dictionary still be shared even though
|
| - * the nodes are being copied rather than moved?
|
| - */
|
| - fake->dict = doc->dict;
|
| - xmlDictReference(doc->dict);
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "reusing dictionary from %s for embedded stylesheet\n",
|
| - doc->URL);
|
| -#endif
|
| -
|
| - newtree = xmlDocCopyNode(subtree, fake, 1);
|
| -
|
| - fake->URL = xmlNodeGetBase(doc, subtree->parent);
|
| -#ifdef WITH_XSLT_DEBUG
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "set base URI for embedded stylesheet as %s\n",
|
| - fake->URL);
|
| -#endif
|
| -
|
| - /*
|
| - * Add all namespaces in scope of embedded stylesheet to
|
| - * root element of newly created stylesheet document
|
| - */
|
| - while ((subtree = subtree->parent) != (xmlNodePtr)doc) {
|
| - for (ns = subtree->ns; ns; ns = ns->next) {
|
| - xmlNewNs(newtree, ns->href, ns->prefix);
|
| - }
|
| - }
|
| -
|
| - xmlAddChild((xmlNodePtr)fake, newtree);
|
| - ret = xsltParseStylesheetDoc(fake);
|
| - if (ret == NULL)
|
| - xmlFreeDoc(fake);
|
| - }
|
| - }
|
| - } else {
|
| - xmlChar *URL, *base;
|
| -
|
| - /*
|
| - * Reference to an external stylesheet
|
| - */
|
| -
|
| - base = xmlNodeGetBase(doc, (xmlNodePtr) doc);
|
| - URL = xmlBuildURI(href, base);
|
| - if (URL != NULL) {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltLoadStylesheetPI : fetching %s\n", URL);
|
| -#endif
|
| - ret = xsltParseStylesheetFile(URL);
|
| - xmlFree(URL);
|
| - } else {
|
| -#ifdef WITH_XSLT_DEBUG_PARSING
|
| - xsltGenericDebug(xsltGenericDebugContext,
|
| - "xsltLoadStylesheetPI : fetching %s\n", href);
|
| -#endif
|
| - ret = xsltParseStylesheetFile(href);
|
| - }
|
| - if (base != NULL)
|
| - xmlFree(base);
|
| - }
|
| - xmlFreeURI(URI);
|
| - xmlFree(href);
|
| - }
|
| - return(ret);
|
| -}
|
|
|