mirror of
https://gitlab.gnome.org/GNOME/libxslt
synced 2025-08-08 21:42:07 +03:00
Refactored xsltValueOf(). Changed to use xmlXPathCastToString() directly,
* libxslt/attributes.c libxslt/documents.c libxslt/functions.c libxslt/keys.c libxslt/namespaces.c libxslt/pattern.c libxslt/preproc.c libxslt/templates.c libxslt/templates.h libxslt/transform.c libxslt/variables.c libxslt/xslt.c libxslt/xsltInternals.h libxslt/xsltutils.c libxslt/xsltutils.h libexslt/common.c libexslt/dynamic.c libexslt/functions.c libexslt/strings.c: Refactored xsltValueOf(). Changed to use xmlXPathCastToString() directly, rather than creating an intermediate object with xmlXPathConvertString(). This now does not add a text-node to the result if the string is empty (this has impact on serialization, since an empty text-node is serialized as <foo></foo>, and now it will be serialized as <foo/>). Refactored other functions in transform.c: Mostly code cleanup/restructuring. Minimized number of function variables for instruction which eat up function stack memory when recursing templates (xsltIf(), xsltChoose(), xsltApplyTemplates(), xsltCallTemplate()). Changed XSLT tests to use xmlXPathCompiledEvalToBoolean(). Implemented redefinition checks at compilation-time and eliminating them at transformation time in the refactored code paths. Introduced the field @currentTemplateRule on xsltTransformContext to reflect the "Current Template Rule" as defined by the spec. NOTE that ctxt->currentTemplateRule and ctxt->templ is not the same; the former is the "Current Template Rule" as defined by the XSLT spec, the latter is simply the template struct being currently processed by Libxslt. Added XML_COMMENT_NODE and XML_CDATA_SECTION_NODE to the macro IS_XSLT_REAL_NODE. Misc code cleanup/restructuring and everything else I already forgot. Refactored lifetime of temporary result tree fragments. Substituted all calls to the now deprecated xsltRegisterTmpRVT() for the new xsltRegisterLocalRVT(). Fragments of xsl:variable and xsl:param are freed when the variable/pram is freed. Fragments created when evaluating a "select" of xsl:varible and xsl:param are also bound to the lifetime of the var/param. EXSLT's func:function now uses the following functions to let take care the transformation's garbage collector of returned tree fragments: xsltExtensionInstructionResultRegister(), xsltExtensionInstructionResultFinalize() Fixes: #339222 - xsl:param at invalid position inside an xsl:template is not catched #346015 - Non-declared caller-parameters are accepted #160400 - Compiles invalid XSLT; unbound variable accepted #308441 - namespaced parameters become unregistered #307103 - problem with proximity position in predicates of match patterns #328218 - problem with exsl:node-set() when converting strings to node sets #318088 - infinite recursion detection #321505 - Multiple contiguous CDATA in output #334493 - "--param" option does not have root context #114377 - weird func:result/xsl:variable/exsl:node-set interaction #150309 - Regression caused by fix for 142768
This commit is contained in:
61
ChangeLog
61
ChangeLog
@@ -1,3 +1,64 @@
|
||||
Fri Jul 14 17:55:42 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
|
||||
|
||||
* libxslt/attributes.c libxslt/documents.c
|
||||
libxslt/functions.c libxslt/keys.c libxslt/namespaces.c
|
||||
libxslt/pattern.c libxslt/preproc.c libxslt/templates.c
|
||||
libxslt/templates.h libxslt/transform.c libxslt/variables.c
|
||||
libxslt/xslt.c libxslt/xsltInternals.h libxslt/xsltutils.c
|
||||
libxslt/xsltutils.h libexslt/common.c libexslt/dynamic.c
|
||||
libexslt/functions.c libexslt/strings.c:
|
||||
Refactored xsltValueOf(). Changed to use xmlXPathCastToString()
|
||||
directly, rather than creating an intermediate object with
|
||||
xmlXPathConvertString(). This now does not add a text-node to
|
||||
the result if the string is empty (this has impact on
|
||||
serialization, since an empty text-node is serialized as
|
||||
<foo></foo>, and now it will be serialized as <foo/>).
|
||||
Refactored other functions in transform.c:
|
||||
Mostly code cleanup/restructuring. Minimized number of
|
||||
function variables for instruction which eat up function stack
|
||||
memory when recursing templates (xsltIf(), xsltChoose(),
|
||||
xsltApplyTemplates(), xsltCallTemplate()).
|
||||
Changed XSLT tests to use xmlXPathCompiledEvalToBoolean().
|
||||
Implemented redefinition checks at compilation-time and
|
||||
eliminating them at transformation time in the refactored code
|
||||
paths.
|
||||
Introduced the field @currentTemplateRule on xsltTransformContext to
|
||||
reflect the "Current Template Rule" as defined by the spec.
|
||||
NOTE that ctxt->currentTemplateRule and ctxt->templ is not the
|
||||
same; the former is the "Current Template Rule" as defined by the
|
||||
XSLT spec, the latter is simply the template struct being
|
||||
currently processed by Libxslt.
|
||||
Added XML_COMMENT_NODE and XML_CDATA_SECTION_NODE to the macro
|
||||
IS_XSLT_REAL_NODE.
|
||||
Misc code cleanup/restructuring and everything else I already forgot.
|
||||
Refactored lifetime of temporary result tree fragments.
|
||||
Substituted all calls to the now deprecated xsltRegisterTmpRVT()
|
||||
for the new xsltRegisterLocalRVT().
|
||||
Fragments of xsl:variable and xsl:param are freed when the
|
||||
variable/pram is freed.
|
||||
Fragments created when evaluating a "select" of xsl:varible and
|
||||
xsl:param are also bound to the lifetime of the var/param.
|
||||
EXSLT's func:function now uses the following functions to let take
|
||||
care the transformation's garbage collector of returned tree
|
||||
fragments:
|
||||
xsltExtensionInstructionResultRegister(),
|
||||
xsltExtensionInstructionResultFinalize()
|
||||
Fixes:
|
||||
#339222 - xsl:param at invalid position inside an xsl:template is
|
||||
not catched
|
||||
#346015 - Non-declared caller-parameters are accepted
|
||||
#160400 - Compiles invalid XSLT; unbound variable accepted
|
||||
#308441 - namespaced parameters become unregistered
|
||||
#307103 - problem with proximity position in predicates of match
|
||||
patterns
|
||||
#328218 - problem with exsl:node-set() when converting strings
|
||||
to node sets
|
||||
#318088 - infinite recursion detection
|
||||
#321505 - Multiple contiguous CDATA in output
|
||||
#334493 - "--param" option does not have root context
|
||||
#114377 - weird func:result/xsl:variable/exsl:node-set interaction
|
||||
#150309 - Regression caused by fix for 142768
|
||||
|
||||
Wed Jun 21 15:13:27 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
|
||||
|
||||
* tests/docs/bug-54.xml tests/general/bug-54.out
|
||||
|
@@ -23,34 +23,49 @@
|
||||
|
||||
static void
|
||||
exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
xmlChar *strval;
|
||||
xmlNodePtr retNode;
|
||||
xmlXPathObjectPtr ret;
|
||||
|
||||
if (nargs != 1) {
|
||||
xmlXPathSetArityError(ctxt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xmlXPathStackIsNodeSet (ctxt)) {
|
||||
xsltFunctionNodeSet (ctxt, nargs);
|
||||
return;
|
||||
} else {
|
||||
xmlDocPtr fragment;
|
||||
xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
|
||||
xmlNodePtr txt;
|
||||
xmlChar *strval;
|
||||
xmlXPathObjectPtr obj;
|
||||
/*
|
||||
* SPEC EXSLT:
|
||||
* "You can also use this function to turn a string into a text
|
||||
* node, which is helpful if you want to pass a string to a
|
||||
* function that only accepts a node-set."
|
||||
*/
|
||||
fragment = xsltCreateRVT(tctxt);
|
||||
if (fragment == NULL) {
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"exsltNodeSetFunction: Failed to create a tree fragment.\n");
|
||||
tctxt->state = XSLT_STATE_STOPPED;
|
||||
return;
|
||||
}
|
||||
xsltRegisterLocalRVT(tctxt, fragment);
|
||||
|
||||
strval = xmlXPathPopString (ctxt);
|
||||
retNode = xmlNewDocText (NULL, strval);
|
||||
ret = xmlXPathNewValueTree (retNode);
|
||||
if (ret == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"exsltNodeSetFunction: ret == NULL\n");
|
||||
} else {
|
||||
ret->type = XPATH_NODESET;
|
||||
}
|
||||
|
||||
txt = xmlNewDocText (fragment, strval);
|
||||
xmlAddChild((xmlNodePtr) fragment, txt);
|
||||
obj = xmlXPathNewNodeSet(txt);
|
||||
if (obj == NULL) {
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"exsltNodeSetFunction: Failed to create a node set object.\n");
|
||||
tctxt->state = XSLT_STATE_STOPPED;
|
||||
}
|
||||
if (strval != NULL)
|
||||
xmlFree (strval);
|
||||
|
||||
valuePush (ctxt, ret);
|
||||
valuePush (ctxt, obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -149,7 +149,7 @@ exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
||||
*/
|
||||
container = xsltCreateRVT(xsltXPathGetTransformContext(ctxt));
|
||||
if (container != NULL)
|
||||
xsltRegisterTmpRVT(xsltXPathGetTransformContext(ctxt), container);
|
||||
xsltRegisterLocalRVT(xsltXPathGetTransformContext(ctxt), container);
|
||||
|
||||
if (nodeset && nodeset->nodeNr > 0) {
|
||||
xmlXPathNodeSetSort(nodeset);
|
||||
|
@@ -35,6 +35,7 @@ struct _exsltFuncData {
|
||||
xmlHashTablePtr funcs; /* pointer to the stylesheet module data */
|
||||
xmlXPathObjectPtr result; /* returned by func:result */
|
||||
int error; /* did an error occur? */
|
||||
xmlDocPtr RVT; /* result tree fragment */
|
||||
};
|
||||
|
||||
typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp;
|
||||
@@ -56,6 +57,8 @@ static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt,
|
||||
int nargs);
|
||||
static exsltFuncFunctionData *exsltFuncNewFunctionData(void);
|
||||
|
||||
static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";
|
||||
|
||||
/**
|
||||
* exsltFuncRegisterFunc:
|
||||
* @func: the #exsltFuncFunctionData for the function
|
||||
@@ -274,7 +277,7 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
xmlXPathObjectPtr obj, oldResult, ret;
|
||||
exsltFuncData *data;
|
||||
exsltFuncFunctionData *func;
|
||||
xmlNodePtr paramNode, oldInsert, fake, content = NULL;
|
||||
xmlNodePtr paramNode, oldInsert, fake;
|
||||
int oldBase;
|
||||
xsltStackElemPtr params = NULL, param;
|
||||
xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
|
||||
@@ -304,7 +307,6 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
}
|
||||
if (func->content != NULL) {
|
||||
paramNode = func->content->prev;
|
||||
content = func->content;
|
||||
}
|
||||
else
|
||||
paramNode = NULL;
|
||||
@@ -314,16 +316,36 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
"param == NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* set params */
|
||||
/*
|
||||
* Process xsl:param instructions which were not set by the
|
||||
* invoking function call.
|
||||
*/
|
||||
for (i = func->nargs; (i > nargs) && (paramNode != NULL); i--) {
|
||||
/*
|
||||
* Those are the xsl:param instructions, which were not
|
||||
* set by the calling function.
|
||||
*/
|
||||
param = xsltParseStylesheetCallerParam (tctxt, paramNode);
|
||||
param->next = params;
|
||||
params = param;
|
||||
paramNode = paramNode->prev;
|
||||
if (content != NULL)
|
||||
content = content->prev;
|
||||
}
|
||||
/*
|
||||
* Process xsl:param instructions which are set by the
|
||||
* invoking function call.
|
||||
*/
|
||||
while ((i-- > 0) && (paramNode != NULL)) {
|
||||
obj = valuePop(ctxt);
|
||||
/* FIXME: this is a bit hackish */
|
||||
/*
|
||||
* TODO: Using xsltParseStylesheetCallerParam() is actually
|
||||
* not correct, since we are processing an xsl:param; but
|
||||
* using xsltParseStylesheetParam() won't work, as it puts
|
||||
* the param on the varible stack and does not give access to
|
||||
* the created xsltStackElemPtr.
|
||||
* It's also not correct, as xsltParseStylesheetCallerParam()
|
||||
* will report error messages indicating an "xsl:with-param" and
|
||||
* not the actual "xsl:param".
|
||||
*/
|
||||
param = xsltParseStylesheetCallerParam (tctxt, paramNode);
|
||||
param->computed = 1;
|
||||
if (param->value != NULL)
|
||||
@@ -348,18 +370,18 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
oldBase = tctxt->varsBase;
|
||||
tctxt->varsBase = tctxt->varsNr;
|
||||
xsltApplyOneTemplate (tctxt, xmlXPathGetContextNode(ctxt),
|
||||
content, NULL, params);
|
||||
func->content, NULL, params);
|
||||
tctxt->insert = oldInsert;
|
||||
tctxt->varsBase = oldBase; /* restore original scope */
|
||||
if (params != NULL)
|
||||
xsltFreeStackElemList(params);
|
||||
|
||||
if (data->error != 0)
|
||||
return;
|
||||
goto error;
|
||||
|
||||
if (data->result != NULL)
|
||||
if (data->result != NULL) {
|
||||
ret = data->result;
|
||||
else
|
||||
} else
|
||||
ret = xmlXPathNewCString("");
|
||||
|
||||
data->result = oldResult;
|
||||
@@ -377,10 +399,18 @@ exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
"executing a function\n",
|
||||
ctxt->context->functionURI, ctxt->context->function);
|
||||
xmlFreeNode(fake);
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
xmlFreeNode(fake);
|
||||
valuePush(ctxt, ret);
|
||||
|
||||
error:
|
||||
/*
|
||||
* IMPORTANT: This enables previously tree fragments marked as
|
||||
* being results of a function, to be garbage-collected after
|
||||
* the calling process exits.
|
||||
*/
|
||||
xsltExtensionInstructionResultFinalize(tctxt);
|
||||
}
|
||||
|
||||
|
||||
@@ -569,8 +599,7 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
||||
exsltFuncResultPreComp *comp) {
|
||||
exsltFuncData *data;
|
||||
xmlXPathObjectPtr ret;
|
||||
xmlNsPtr *oldNsList;
|
||||
int oldNsNr;
|
||||
|
||||
|
||||
/* It is an error if instantiating the content of the
|
||||
* func:function element results in the instantiation of more than
|
||||
@@ -592,6 +621,9 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
||||
* Processing
|
||||
*/
|
||||
if (comp->select != NULL) {
|
||||
xmlNsPtr *oldXPNsList;
|
||||
int oldXPNsNr;
|
||||
xmlNodePtr oldXPContextNode;
|
||||
/* If the func:result element has a select attribute, then the
|
||||
* value of the attribute must be an expression and the
|
||||
* returned value is the object that results from evaluating
|
||||
@@ -604,18 +636,29 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
||||
data->error = 1;
|
||||
return;
|
||||
}
|
||||
oldNsList = ctxt->xpathCtxt->namespaces;
|
||||
oldNsNr = ctxt->xpathCtxt->nsNr;
|
||||
oldXPNsList = ctxt->xpathCtxt->namespaces;
|
||||
oldXPNsNr = ctxt->xpathCtxt->nsNr;
|
||||
oldXPContextNode = ctxt->xpathCtxt->node;
|
||||
|
||||
ctxt->xpathCtxt->namespaces = comp->nsList;
|
||||
ctxt->xpathCtxt->nsNr = comp->nsNr;
|
||||
|
||||
ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt);
|
||||
ctxt->xpathCtxt->nsNr = oldNsNr;
|
||||
ctxt->xpathCtxt->namespaces = oldNsList;
|
||||
|
||||
ctxt->xpathCtxt->node = oldXPContextNode;
|
||||
ctxt->xpathCtxt->nsNr = oldXPNsNr;
|
||||
ctxt->xpathCtxt->namespaces = oldXPNsList;
|
||||
|
||||
if (ret == NULL) {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"exsltFuncResultElem: ret == NULL\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Mark it as a function result in order to avoid garbage
|
||||
* collecting of tree fragments before the function exits.
|
||||
*/
|
||||
xsltExtensionInstructionResultRegister(ctxt, ret);
|
||||
} else if (inst->children != NULL) {
|
||||
/* If the func:result element does not have a select attribute
|
||||
* and has non-empty content (i.e. the func:result element has
|
||||
@@ -632,7 +675,8 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
||||
data->error = 1;
|
||||
return;
|
||||
}
|
||||
xsltRegisterTmpRVT(ctxt, container);
|
||||
xsltRegisterLocalRVT(ctxt, container);
|
||||
|
||||
oldInsert = ctxt->insert;
|
||||
ctxt->insert = (xmlNodePtr) container;
|
||||
xsltApplyOneTemplate (ctxt, ctxt->xpathCtxt->node,
|
||||
@@ -646,6 +690,11 @@ exsltFuncResultElem (xsltTransformContextPtr ctxt,
|
||||
data->error = 1;
|
||||
} else {
|
||||
ret->boolval = 0; /* Freeing is not handled there anymore */
|
||||
/*
|
||||
* Mark it as a function result in order to avoid garbage
|
||||
* collecting of tree fragments before the function exits.
|
||||
*/
|
||||
xsltExtensionInstructionResultRegister(ctxt, ret);
|
||||
}
|
||||
} else {
|
||||
/* If the func:result element has empty content and does not
|
||||
|
@@ -71,10 +71,9 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
||||
|
||||
container = xsltCreateRVT(tctxt);
|
||||
if (container != NULL) {
|
||||
xsltRegisterTmpRVT(tctxt, container);
|
||||
xsltRegisterLocalRVT(tctxt, container);
|
||||
ret = xmlXPathNewNodeSet(NULL);
|
||||
if (ret != NULL) {
|
||||
ret->boolval = 0; /* Freeing is not handled there anymore */
|
||||
for (cur = str, token = str; *cur != 0; cur += clen) {
|
||||
clen = xmlUTF8Size(cur);
|
||||
if (*delimiters == 0) { /* empty string case */
|
||||
@@ -174,12 +173,14 @@ exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* OPTIMIZE TODO: We are creating an xmlDoc for every split!
|
||||
*/
|
||||
container = xsltCreateRVT(tctxt);
|
||||
if (container != NULL) {
|
||||
xsltRegisterTmpRVT(tctxt, container);
|
||||
xsltRegisterLocalRVT(tctxt, container);
|
||||
ret = xmlXPathNewNodeSet(NULL);
|
||||
if (ret != NULL) {
|
||||
ret->boolval = 0; /* Freeing is not handled there anymore */
|
||||
for (cur = str, token = str; *cur != 0; cur++) {
|
||||
if (delimiterLength == 0) {
|
||||
if (cur != token) {
|
||||
|
@@ -638,7 +638,7 @@ xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
|
||||
*/
|
||||
static void
|
||||
xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr currentNode,
|
||||
xmlNodePtr contextNode,
|
||||
xmlNodePtr inst,
|
||||
xsltStylePreCompPtr castedComp,
|
||||
int fromAttributeSet)
|
||||
@@ -656,7 +656,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
xmlNsPtr ns = NULL;
|
||||
xmlAttrPtr attr;
|
||||
|
||||
if ((ctxt == NULL) || (currentNode == NULL) || (inst == NULL))
|
||||
if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -681,7 +681,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
if (comp == NULL) {
|
||||
xsltTransformError(ctxt, NULL, inst,
|
||||
"Internal error in xsltAttributeInternal(): "
|
||||
"The instruction was no compiled.\n");
|
||||
"The XSLT 'attribute' instruction was not compiled.\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@@ -731,7 +731,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
|
||||
#ifdef WITH_DEBUGGER
|
||||
if (ctxt->debugStatus != XSLT_DEBUG_NONE)
|
||||
xslHandleDebugger(inst, currentNode, NULL, ctxt);
|
||||
xslHandleDebugger(inst, contextNode, NULL, ctxt);
|
||||
#endif
|
||||
|
||||
if (comp->name == NULL) {
|
||||
@@ -875,8 +875,10 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
* tree fragment.
|
||||
*/
|
||||
if (nsName != NULL) {
|
||||
ns = xsltTreeAcquireStoredNs(ctxt->document->doc, nsName,
|
||||
prefix);
|
||||
/*
|
||||
* TODO: Get the doc of @targetElem.
|
||||
*/
|
||||
ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -980,7 +982,7 @@ xsltAttributeInternal(xsltTransformContextPtr ctxt,
|
||||
/*
|
||||
* The sequence constructor might be complex, so instantiate it.
|
||||
*/
|
||||
value = xsltEvalTemplateString(ctxt, currentNode, inst);
|
||||
value = xsltEvalTemplateString(ctxt, contextNode, inst);
|
||||
if (value != NULL) {
|
||||
attr = xmlSetNsProp(ctxt->insert, ns, name, value);
|
||||
xmlFree(value);
|
||||
|
@@ -410,7 +410,9 @@ xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
|
||||
* @ctxt: an XSLT transformation context
|
||||
* @doc: a parsed XML document
|
||||
*
|
||||
* Try to find a document within the XSLT transformation context
|
||||
* Try to find a document within the XSLT transformation context.
|
||||
* This will not find document infos for temporary
|
||||
* Result Tree Fragments.
|
||||
*
|
||||
* Returns the desired xsltDocumentPtr or NULL in case of error
|
||||
*/
|
||||
|
@@ -107,14 +107,14 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
xsltTransformContextPtr tctxt;
|
||||
xmlURIPtr uri;
|
||||
xmlChar *fragment;
|
||||
xsltDocumentPtr xsltdoc;
|
||||
xsltDocumentPtr idoc; /* document info */
|
||||
xmlDocPtr doc;
|
||||
xmlXPathContextPtr xptrctxt = NULL;
|
||||
xmlXPathObjectPtr object = NULL;
|
||||
xmlXPathObjectPtr resObj = NULL;
|
||||
|
||||
tctxt = xsltXPathGetTransformContext(ctxt);
|
||||
if (tctxt == NULL) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(NULL, NULL, NULL,
|
||||
"document() : internal error tctxt == NULL\n");
|
||||
valuePush(ctxt, xmlXPathNewNodeSet(NULL));
|
||||
return;
|
||||
@@ -122,7 +122,7 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
|
||||
uri = xmlParseURI((const char *) URI);
|
||||
if (uri == NULL) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(tctxt, NULL, NULL,
|
||||
"document() : failed to parse URI\n");
|
||||
valuePush(ctxt, xmlXPathNewNodeSet(NULL));
|
||||
return;
|
||||
@@ -135,16 +135,20 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
if (fragment != NULL) {
|
||||
uri->fragment = NULL;
|
||||
URI = xmlSaveUri(uri);
|
||||
xsltdoc = xsltLoadDocument(tctxt, URI);
|
||||
idoc = xsltLoadDocument(tctxt, URI);
|
||||
xmlFree(URI);
|
||||
} else
|
||||
xsltdoc = xsltLoadDocument(tctxt, URI);
|
||||
idoc = xsltLoadDocument(tctxt, URI);
|
||||
xmlFreeURI(uri);
|
||||
|
||||
if (xsltdoc == NULL) {
|
||||
if (idoc == NULL) {
|
||||
if ((URI == NULL) ||
|
||||
(URI[0] == '#') ||
|
||||
(xmlStrEqual(tctxt->style->doc->URL, URI))) {
|
||||
(xmlStrEqual(tctxt->style->doc->URL, URI)))
|
||||
{
|
||||
/*
|
||||
* This selects the stylesheet's doc itself.
|
||||
*/
|
||||
doc = tctxt->style->doc;
|
||||
} else {
|
||||
valuePush(ctxt, xmlXPathNewNodeSet(NULL));
|
||||
@@ -155,11 +159,10 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
return;
|
||||
}
|
||||
} else
|
||||
doc = xsltdoc->doc;
|
||||
doc = idoc->doc;
|
||||
|
||||
if (fragment == NULL) {
|
||||
valuePush(ctxt,
|
||||
xmlXPathNewNodeSet((xmlNodePtr) doc));
|
||||
valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,21 +170,20 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
#ifdef LIBXML_XPTR_ENABLED
|
||||
xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
|
||||
if (xptrctxt == NULL) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(tctxt, NULL, NULL,
|
||||
"document() : internal error xptrctxt == NULL\n");
|
||||
goto out_fragment;
|
||||
}
|
||||
|
||||
object = xmlXPtrEval(fragment, xptrctxt);
|
||||
resObj = xmlXPtrEval(fragment, xptrctxt);
|
||||
xmlXPathFreeContext(xptrctxt);
|
||||
#endif
|
||||
xmlFree(fragment);
|
||||
if (xptrctxt != NULL)
|
||||
xmlXPathFreeContext(xptrctxt);
|
||||
|
||||
if (object == NULL)
|
||||
if (resObj == NULL)
|
||||
goto out_fragment;
|
||||
|
||||
switch (object->type) {
|
||||
switch (resObj->type) {
|
||||
case XPATH_NODESET:
|
||||
break;
|
||||
case XPATH_UNDEFINED:
|
||||
@@ -193,17 +195,17 @@ xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
|
||||
case XPATH_XSLT_TREE:
|
||||
case XPATH_RANGE:
|
||||
case XPATH_LOCATIONSET:
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(tctxt, NULL, NULL,
|
||||
"document() : XPointer does not select a node set: #%s\n",
|
||||
fragment);
|
||||
goto out_object;
|
||||
}
|
||||
|
||||
valuePush(ctxt, object);
|
||||
valuePush(ctxt, resObj);
|
||||
return;
|
||||
|
||||
out_object:
|
||||
xmlXPathFreeObject(object);
|
||||
xmlXPathFreeObject(resObj);
|
||||
|
||||
out_fragment:
|
||||
valuePush(ctxt, xmlXPathNewNodeSet(NULL));
|
||||
@@ -346,13 +348,7 @@ xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
|
||||
*/
|
||||
void
|
||||
xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
xmlNodeSetPtr nodelist;
|
||||
xmlXPathObjectPtr obj1, obj2;
|
||||
xmlChar *key = NULL, *value;
|
||||
const xmlChar *keyURI;
|
||||
xsltTransformContextPtr tctxt;
|
||||
xsltDocumentPtr oldDocumentPtr;
|
||||
xmlDocPtr oldXPathDocPtr;
|
||||
|
||||
if (nargs != 2) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
@@ -361,6 +357,9 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the key's value.
|
||||
*/
|
||||
obj2 = valuePop(ctxt);
|
||||
xmlXPathStringFunction(ctxt, 1);
|
||||
if ((obj2 == NULL) ||
|
||||
@@ -372,6 +371,9 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Get the key's name.
|
||||
*/
|
||||
obj1 = valuePop(ctxt);
|
||||
|
||||
if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
|
||||
@@ -395,8 +397,26 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
}
|
||||
valuePush(ctxt, ret);
|
||||
} else {
|
||||
xmlNodeSetPtr nodelist = NULL;
|
||||
xmlChar *key = NULL, *value;
|
||||
const xmlChar *keyURI;
|
||||
xsltTransformContextPtr tctxt;
|
||||
xmlChar *qname, *prefix;
|
||||
xmlXPathContextPtr xpctxt = ctxt->context;
|
||||
xmlNodePtr tmpNode = NULL;
|
||||
xsltDocumentPtr oldDocInfo;
|
||||
|
||||
tctxt = xsltXPathGetTransformContext(ctxt);
|
||||
|
||||
oldDocInfo = tctxt->document;
|
||||
|
||||
if (xpctxt->node == NULL) {
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"Internal error in xsltKeyFunction(): "
|
||||
"The context node is not set on the XPath context.\n");
|
||||
tctxt->state = XSLT_STATE_STOPPED;
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Get the associated namespace URI if qualified name
|
||||
*/
|
||||
@@ -409,10 +429,13 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
if (prefix != NULL) {
|
||||
keyURI = xmlXPathNsLookup(ctxt->context, prefix);
|
||||
keyURI = xmlXPathNsLookup(xpctxt, prefix);
|
||||
if (keyURI == NULL) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"key() : prefix %s is not bound\n", prefix);
|
||||
/*
|
||||
* TODO: Shouldn't we stop here?
|
||||
*/
|
||||
}
|
||||
xmlFree(prefix);
|
||||
} else {
|
||||
@@ -426,59 +449,90 @@ xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
|
||||
valuePush(ctxt, obj2);
|
||||
xmlXPathStringFunction(ctxt, 1);
|
||||
if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
|
||||
xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"key() : invalid arg expecting a string\n");
|
||||
ctxt->error = XPATH_INVALID_TYPE;
|
||||
xmlXPathFreeObject(obj1);
|
||||
|
||||
return;
|
||||
goto error;
|
||||
}
|
||||
obj2 = valuePop(ctxt);
|
||||
value = obj2->stringval;
|
||||
|
||||
tctxt = xsltXPathGetTransformContext(ctxt);
|
||||
oldDocumentPtr = tctxt->document;
|
||||
oldXPathDocPtr = tctxt->xpathCtxt->doc;
|
||||
if ((ctxt->context->doc != NULL) &&
|
||||
(tctxt->document->doc != ctxt->context->doc)) {
|
||||
/*
|
||||
* The xpath context document needs to be changed. If the
|
||||
* current context document is a node-set, we must use an
|
||||
* xsltDocument associated with the node-set, which may or
|
||||
* may not currently exist.
|
||||
* We need to ensure that ctxt->document is available for
|
||||
* xsltGetKey().
|
||||
* First find the relevant doc, which is the context node's
|
||||
* owner doc; using context->doc is not safe, since
|
||||
* the doc could have been acquired via the document() function,
|
||||
* or the doc might be a Result Tree Fragment.
|
||||
* FUTURE INFO: In XSLT 2.0 the key() function takes an additional
|
||||
* argument indicating the doc to use.
|
||||
*/
|
||||
if (xmlStrEqual((const xmlChar *)ctxt->context->doc->name,
|
||||
BAD_CAST " fake node libxslt")) { /* node-set */
|
||||
if (xpctxt->node->type == XML_NAMESPACE_DECL) {
|
||||
/*
|
||||
* Check whether we already have an xsltDocument set up
|
||||
* REVISIT: This is a libxml hack! Check xpath.c for details.
|
||||
* The XPath module sets the owner element of a ns-node on
|
||||
* the ns->next field.
|
||||
*/
|
||||
if (ctxt->context->doc->_private == NULL) /* nope */
|
||||
ctxt->context->doc->_private =
|
||||
xsltNewDocument(tctxt, ctxt->context->doc);
|
||||
tctxt->document = ctxt->context->doc->_private;
|
||||
if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&
|
||||
(((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))
|
||||
{
|
||||
tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;
|
||||
}
|
||||
else {
|
||||
tctxt->document = xsltFindDocument(tctxt, ctxt->context->doc);
|
||||
if (tctxt->document == NULL)
|
||||
tctxt->document = oldDocumentPtr;
|
||||
else
|
||||
tctxt->xpathCtxt->doc = ctxt->context->doc;
|
||||
}
|
||||
}
|
||||
nodelist = xsltGetKey(tctxt, key, keyURI, value);
|
||||
tctxt->document = oldDocumentPtr;
|
||||
tctxt->xpathCtxt->doc = oldXPathDocPtr;
|
||||
valuePush(ctxt, xmlXPathWrapNodeSet(
|
||||
xmlXPathNodeSetMerge(NULL, nodelist)));
|
||||
} else
|
||||
tmpNode = xpctxt->node;
|
||||
|
||||
if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"Internal error in xsltKeyFunction(): "
|
||||
"Couldn't get the doc of the XPath context node.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((tctxt->document == NULL) ||
|
||||
(tctxt->document->doc != tmpNode->doc))
|
||||
{
|
||||
if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {
|
||||
/*
|
||||
* This is a Result Tree Fragment.
|
||||
*/
|
||||
if (tmpNode->doc->_private == NULL) {
|
||||
tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);
|
||||
if (tmpNode->doc->_private == NULL)
|
||||
goto error;
|
||||
}
|
||||
tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private;
|
||||
} else {
|
||||
/*
|
||||
* May be the initial source doc or a doc acquired via the
|
||||
* document() function.
|
||||
*/
|
||||
tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);
|
||||
}
|
||||
if (tctxt->document == NULL) {
|
||||
xsltTransformError(tctxt, NULL, tctxt->inst,
|
||||
"Internal error in xsltKeyFunction(): "
|
||||
"Could not get the document info of a context doc.\n");
|
||||
tctxt->state = XSLT_STATE_STOPPED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Get/compute the key value.
|
||||
*/
|
||||
nodelist = xsltGetKey(tctxt, key, keyURI, value);
|
||||
|
||||
error:
|
||||
tctxt->document = oldDocInfo;
|
||||
valuePush(ctxt, xmlXPathWrapNodeSet(
|
||||
xmlXPathNodeSetMerge(NULL, nodelist)));
|
||||
if (key != NULL)
|
||||
xmlFree(key);
|
||||
}
|
||||
|
||||
if (obj1 != NULL)
|
||||
xmlXPathFreeObject(obj1);
|
||||
if (obj2 != NULL)
|
||||
xmlXPathFreeObject(obj2);
|
||||
if (key != NULL)
|
||||
xmlFree(key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
319
libxslt/keys.c
319
libxslt/keys.c
@@ -382,7 +382,9 @@ error:
|
||||
* @nameURI: the name URI or NULL
|
||||
* @value: the key value to look for
|
||||
*
|
||||
* Lookup a key
|
||||
* Looks up a key of the in current source doc (the document info
|
||||
* on @ctxt->document). Computes the key if not already done
|
||||
* for the current source doc.
|
||||
*
|
||||
* Returns the nodeset resulting from the query or NULL
|
||||
*/
|
||||
@@ -403,6 +405,7 @@ xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
xsltGenericDebug(xsltGenericDebugContext,
|
||||
"Get key %s, value %s\n", name, value);
|
||||
#endif
|
||||
|
||||
table = (xsltKeyTablePtr) ctxt->document->keys;
|
||||
while (table != NULL) {
|
||||
if (((nameURI != NULL) == (table->nameURI != NULL)) &&
|
||||
@@ -464,6 +467,7 @@ xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name,
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#if 0 /* Merged with xsltInitCtxtKey() */
|
||||
/**
|
||||
* xsltEvalXPathKeys:
|
||||
* @ctxt: the XSLT transformation context
|
||||
@@ -547,104 +551,117 @@ xsltEvalXPathKeys(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp,
|
||||
ctxt->xpathCtxt->namespaces = oldNamespaces;
|
||||
return(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* xsltInitCtxtKey:
|
||||
* @ctxt: an XSLT transformation context
|
||||
* @doc: an XSLT document
|
||||
* @keyd: the key definition
|
||||
* @idoc: the document information (holds key values)
|
||||
* @keyDef: the key definition
|
||||
*
|
||||
* Computes the key tables this key and for the current input document.
|
||||
*/
|
||||
int
|
||||
xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr doc,
|
||||
xsltKeyDefPtr keyd) {
|
||||
int i;
|
||||
xmlNodeSetPtr nodelist = NULL, keylist;
|
||||
xmlXPathObjectPtr res = NULL;
|
||||
xmlChar *str, **list;
|
||||
xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc,
|
||||
xsltKeyDefPtr keyDef)
|
||||
{
|
||||
int i, len, k;
|
||||
xmlNodeSetPtr matchList = NULL, keylist;
|
||||
xmlXPathObjectPtr matchRes = NULL, useRes = NULL;
|
||||
xmlChar *str = NULL;
|
||||
xsltKeyTablePtr table;
|
||||
int oldPos, oldSize;
|
||||
xmlNodePtr oldInst;
|
||||
xmlNodePtr oldNode;
|
||||
xsltDocumentPtr oldDoc;
|
||||
xmlDocPtr oldXDoc;
|
||||
int oldNsNr;
|
||||
xmlNsPtr *oldNamespaces;
|
||||
xmlNodePtr oldInst, cur;
|
||||
xmlNodePtr oldContextNode;
|
||||
xsltDocumentPtr oldDocInfo;
|
||||
int oldXPPos, oldXPSize;
|
||||
xmlDocPtr oldXPDoc;
|
||||
int oldXPNsNr;
|
||||
xmlNsPtr *oldXPNamespaces;
|
||||
xmlXPathContextPtr xpctxt;
|
||||
|
||||
doc->nbKeysComputed++;
|
||||
if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL))
|
||||
return(-1);
|
||||
|
||||
xpctxt = ctxt->xpathCtxt;
|
||||
idoc->nbKeysComputed++;
|
||||
/*
|
||||
* Evaluate the nodelist
|
||||
* Save context state.
|
||||
*/
|
||||
|
||||
oldXDoc= ctxt->xpathCtxt->doc;
|
||||
oldPos = ctxt->xpathCtxt->proximityPosition;
|
||||
oldSize = ctxt->xpathCtxt->contextSize;
|
||||
oldNsNr = ctxt->xpathCtxt->nsNr;
|
||||
oldNamespaces = ctxt->xpathCtxt->namespaces;
|
||||
oldInst = ctxt->inst;
|
||||
oldDoc = ctxt->document;
|
||||
oldNode = ctxt->node;
|
||||
oldDocInfo = ctxt->document;
|
||||
oldContextNode = ctxt->node;
|
||||
|
||||
if (keyd->comp == NULL)
|
||||
goto error;
|
||||
if (keyd->usecomp == NULL)
|
||||
goto error;
|
||||
oldXPDoc = xpctxt->doc;
|
||||
oldXPPos = xpctxt->proximityPosition;
|
||||
oldXPSize = xpctxt->contextSize;
|
||||
oldXPNsNr = xpctxt->nsNr;
|
||||
oldXPNamespaces = xpctxt->namespaces;
|
||||
|
||||
ctxt->document = doc;
|
||||
ctxt->xpathCtxt->doc = doc->doc;
|
||||
ctxt->xpathCtxt->node = (xmlNodePtr) doc->doc;
|
||||
ctxt->node = (xmlNodePtr) doc->doc;
|
||||
/*
|
||||
* Set up contexts.
|
||||
*/
|
||||
ctxt->document = idoc;
|
||||
ctxt->node = (xmlNodePtr) idoc->doc;
|
||||
ctxt->inst = keyDef->inst;
|
||||
|
||||
xpctxt->doc = idoc->doc;
|
||||
xpctxt->node = (xmlNodePtr) idoc->doc;
|
||||
/* TODO : clarify the use of namespaces in keys evaluation */
|
||||
ctxt->xpathCtxt->namespaces = keyd->nsList;
|
||||
ctxt->xpathCtxt->nsNr = keyd->nsNr;
|
||||
ctxt->inst = keyd->inst;
|
||||
res = xmlXPathCompiledEval(keyd->comp, ctxt->xpathCtxt);
|
||||
ctxt->xpathCtxt->contextSize = oldSize;
|
||||
ctxt->xpathCtxt->proximityPosition = oldPos;
|
||||
ctxt->inst = oldInst;
|
||||
xpctxt->namespaces = keyDef->nsList;
|
||||
xpctxt->nsNr = keyDef->nsNr;
|
||||
|
||||
/*
|
||||
* Evaluate the 'match' expression of the xsl:key.
|
||||
* TODO: The 'match' is a *pattern*.
|
||||
*/
|
||||
matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt);
|
||||
if (matchRes == NULL) {
|
||||
|
||||
if (res != NULL) {
|
||||
if (res->type == XPATH_NODESET) {
|
||||
nodelist = res->nodesetval;
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
if (nodelist != NULL)
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsltInitCtxtKey: %s evaluation failed\n", keyDef->match));
|
||||
#endif
|
||||
xsltTransformError(ctxt, NULL, keyDef->inst,
|
||||
"Failed to evaluate the 'match' expression.\n");
|
||||
ctxt->state = XSLT_STATE_STOPPED;
|
||||
goto error;
|
||||
} else {
|
||||
if (matchRes->type == XPATH_NODESET) {
|
||||
matchList = matchRes->nodesetval;
|
||||
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
if (matchList != NULL)
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsltInitCtxtKey: %s evaluates to %d nodes\n",
|
||||
keyd->match, nodelist->nodeNr));
|
||||
keyDef->match, matchList->nodeNr));
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* Is not a node set, but must be.
|
||||
*/
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsltInitCtxtKey: %s is not a node set\n", keyd->match));
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsltInitCtxtKey: %s evaluation failed\n", keyd->match));
|
||||
"xsltInitCtxtKey: %s is not a node set\n", keyDef->match));
|
||||
#endif
|
||||
xsltTransformError(ctxt, NULL, keyDef->inst,
|
||||
"The 'match' expression did not evaluate to a node set.\n");
|
||||
ctxt->state = XSLT_STATE_STOPPED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* for each node in the list evaluate the key and insert the node
|
||||
*/
|
||||
if ((nodelist == NULL) || (nodelist->nodeNr <= 0))
|
||||
goto error;
|
||||
}
|
||||
if ((matchList == NULL) || (matchList->nodeNr <= 0))
|
||||
goto exit;
|
||||
|
||||
/**
|
||||
* Multiple key definitions for the same name are allowed, so
|
||||
* we must check if the key is already present for this doc
|
||||
*/
|
||||
table = (xsltKeyTablePtr) doc->keys;
|
||||
table = (xsltKeyTablePtr) idoc->keys;
|
||||
while (table != NULL) {
|
||||
if (xmlStrEqual(table->name, keyd->name) &&
|
||||
(((keyd->nameURI == NULL) && (table->nameURI == NULL)) ||
|
||||
((keyd->nameURI != NULL) && (table->nameURI != NULL) &&
|
||||
(xmlStrEqual(table->nameURI, keyd->nameURI)))))
|
||||
if (xmlStrEqual(table->name, keyDef->name) &&
|
||||
(((keyDef->nameURI == NULL) && (table->nameURI == NULL)) ||
|
||||
((keyDef->nameURI != NULL) && (table->nameURI != NULL) &&
|
||||
(xmlStrEqual(table->nameURI, keyDef->nameURI)))))
|
||||
break;
|
||||
table = table->next;
|
||||
}
|
||||
@@ -653,112 +670,170 @@ xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr doc,
|
||||
* chain it to the list of keys for the doc
|
||||
*/
|
||||
if (table == NULL) {
|
||||
table = xsltNewKeyTable(keyd->name, keyd->nameURI);
|
||||
table = xsltNewKeyTable(keyDef->name, keyDef->nameURI);
|
||||
if (table == NULL)
|
||||
goto error;
|
||||
table->next = doc->keys;
|
||||
doc->keys = table;
|
||||
table->next = idoc->keys;
|
||||
idoc->keys = table;
|
||||
}
|
||||
|
||||
for (i = 0;i < nodelist->nodeNr;i++) {
|
||||
if (IS_XSLT_REAL_NODE(nodelist->nodeTab[i])) {
|
||||
ctxt->node = nodelist->nodeTab[i];
|
||||
/*
|
||||
* SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!)
|
||||
* "...the use attribute of the xsl:key element is evaluated with x as
|
||||
" the current node and with a node list containing just x as the
|
||||
* current node list"
|
||||
*/
|
||||
xpctxt->contextSize = 1;
|
||||
xpctxt->proximityPosition = 1;
|
||||
|
||||
list = xsltEvalXPathKeys(ctxt, keyd->usecomp, keyd);
|
||||
if (list != NULL) {
|
||||
int ix = 0;
|
||||
for (i = 0; i < matchList->nodeNr; i++) {
|
||||
cur = matchList->nodeTab[i];
|
||||
if (! IS_XSLT_REAL_NODE(cur))
|
||||
continue;
|
||||
xpctxt->node = cur;
|
||||
/*
|
||||
* Process the 'use' of the xsl:key.
|
||||
* SPEC XSLT 1.0:
|
||||
* "The use attribute is an expression specifying the values of
|
||||
* the key; the expression is evaluated once for each node that
|
||||
* matches the pattern."
|
||||
*/
|
||||
if (useRes != NULL)
|
||||
xmlXPathFreeObject(useRes);
|
||||
useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt);
|
||||
if (useRes == NULL) {
|
||||
xsltTransformError(ctxt, NULL, keyDef->inst,
|
||||
"Failed to evaluate the 'use' expression.\n");
|
||||
ctxt->state = XSLT_STATE_STOPPED;
|
||||
break;
|
||||
}
|
||||
if (useRes->type == XPATH_NODESET) {
|
||||
if ((useRes->nodesetval != NULL) &&
|
||||
(useRes->nodesetval->nodeNr != 0))
|
||||
{
|
||||
len = useRes->nodesetval->nodeNr;
|
||||
str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
len = 1;
|
||||
if (useRes->type == XPATH_STRING) {
|
||||
/*
|
||||
* Consume the string value.
|
||||
*/
|
||||
str = useRes->stringval;
|
||||
useRes->stringval = NULL;
|
||||
} else {
|
||||
str = xmlXPathCastToString(useRes);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Process all strings.
|
||||
*/
|
||||
k = 0;
|
||||
while (1) {
|
||||
if (str == NULL)
|
||||
goto next_string;
|
||||
|
||||
str = list[ix++];
|
||||
while (str != NULL) {
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsl:key : node associated to(%s,%s)\n",
|
||||
keyd->name, str));
|
||||
"xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str));
|
||||
#endif
|
||||
|
||||
keylist = xmlHashLookup(table->keys, str);
|
||||
if (keylist == NULL) {
|
||||
keylist = xmlXPathNodeSetCreate(nodelist->nodeTab[i]);
|
||||
keylist = xmlXPathNodeSetCreate(cur);
|
||||
if (keylist == NULL)
|
||||
goto error;
|
||||
xmlHashAddEntry(table->keys, str, keylist);
|
||||
} else {
|
||||
xmlXPathNodeSetAdd(keylist, nodelist->nodeTab[i]);
|
||||
/*
|
||||
* TODO: How do we know if this function failed?
|
||||
*/
|
||||
xmlXPathNodeSetAdd(keylist, cur);
|
||||
}
|
||||
switch (nodelist->nodeTab[i]->type) {
|
||||
switch (cur->type) {
|
||||
case XML_ELEMENT_NODE:
|
||||
case XML_TEXT_NODE:
|
||||
case XML_CDATA_SECTION_NODE:
|
||||
case XML_PI_NODE:
|
||||
case XML_COMMENT_NODE:
|
||||
nodelist->nodeTab[i]->psvi = keyd;
|
||||
cur->psvi = keyDef;
|
||||
break;
|
||||
case XML_ATTRIBUTE_NODE: {
|
||||
xmlAttrPtr attr = (xmlAttrPtr)
|
||||
nodelist->nodeTab[i];
|
||||
attr->psvi = keyd;
|
||||
case XML_ATTRIBUTE_NODE:
|
||||
((xmlAttrPtr) cur)->psvi = keyDef;
|
||||
break;
|
||||
}
|
||||
case XML_DOCUMENT_NODE:
|
||||
case XML_HTML_DOCUMENT_NODE: {
|
||||
xmlDocPtr kdoc = (xmlDocPtr)
|
||||
nodelist->nodeTab[i];
|
||||
kdoc->psvi = keyd;
|
||||
case XML_HTML_DOCUMENT_NODE:
|
||||
((xmlDocPtr) cur)->psvi = keyDef;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
xmlFree(str);
|
||||
str = list[ix++];
|
||||
}
|
||||
xmlFree(list);
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
} else {
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext,
|
||||
"xsl:key : use %s failed to return strings\n",
|
||||
keyd->use));
|
||||
#endif
|
||||
}
|
||||
str = NULL;
|
||||
|
||||
next_string:
|
||||
k++;
|
||||
if (k >= len)
|
||||
break;
|
||||
str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
error:
|
||||
ctxt->document = oldDoc;
|
||||
ctxt->xpathCtxt->doc = oldXDoc;
|
||||
ctxt->xpathCtxt->nsNr = oldNsNr;
|
||||
ctxt->xpathCtxt->namespaces = oldNamespaces;
|
||||
ctxt->node = oldNode;
|
||||
if (res != NULL)
|
||||
xmlXPathFreeObject(res);
|
||||
/*
|
||||
* Restore context state.
|
||||
*/
|
||||
xpctxt->doc = oldXPDoc;
|
||||
xpctxt->nsNr = oldXPNsNr;
|
||||
xpctxt->namespaces = oldXPNamespaces;
|
||||
xpctxt->proximityPosition = oldXPPos;
|
||||
xpctxt->contextSize = oldXPSize;
|
||||
|
||||
ctxt->node = oldContextNode;
|
||||
ctxt->document = oldDocInfo;
|
||||
ctxt->inst = oldInst;
|
||||
|
||||
if (str)
|
||||
xmlFree(str);
|
||||
if (useRes != NULL)
|
||||
xmlXPathFreeObject(useRes);
|
||||
if (matchRes != NULL)
|
||||
xmlXPathFreeObject(matchRes);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltInitCtxtKeys:
|
||||
* @ctxt: an XSLT transformation context
|
||||
* @doc: an XSLT document
|
||||
* @idoc: a document info
|
||||
*
|
||||
* Computes all the keys tables for the current input document.
|
||||
* Should be done before global varibales are initialized.
|
||||
* NOTE: Not used anymore in the refactored code.
|
||||
*/
|
||||
void
|
||||
xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr doc) {
|
||||
xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) {
|
||||
xsltStylesheetPtr style;
|
||||
xsltKeyDefPtr keyd;
|
||||
xsltKeyDefPtr keyDef;
|
||||
|
||||
if ((ctxt == NULL) || (doc == NULL))
|
||||
if ((ctxt == NULL) || (idoc == NULL))
|
||||
return;
|
||||
#ifdef WITH_XSLT_DEBUG_KEYS
|
||||
if ((doc->doc != NULL) && (doc->doc->URL != NULL))
|
||||
if ((idoc->doc != NULL) && (idoc->doc->URL != NULL))
|
||||
XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n",
|
||||
doc->doc->URL));
|
||||
idoc->doc->URL));
|
||||
#endif
|
||||
style = ctxt->style;
|
||||
while (style != NULL) {
|
||||
keyd = (xsltKeyDefPtr) style->keys;
|
||||
while (keyd != NULL) {
|
||||
xsltInitCtxtKey(ctxt, doc, keyd);
|
||||
keyDef = (xsltKeyDefPtr) style->keys;
|
||||
while (keyDef != NULL) {
|
||||
xsltInitCtxtKey(ctxt, idoc, keyDef);
|
||||
|
||||
keyd = keyd->next;
|
||||
keyDef = keyDef->next;
|
||||
}
|
||||
|
||||
style = xsltNextImport(style);
|
||||
@@ -772,8 +847,8 @@ xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr doc) {
|
||||
* Free the keys associated to a document
|
||||
*/
|
||||
void
|
||||
xsltFreeDocumentKeys(xsltDocumentPtr doc) {
|
||||
if (doc != NULL)
|
||||
xsltFreeKeyTableList(doc->keys);
|
||||
xsltFreeDocumentKeys(xsltDocumentPtr idoc) {
|
||||
if (idoc != NULL)
|
||||
xsltFreeKeyTableList(idoc->keys);
|
||||
}
|
||||
|
||||
|
@@ -44,8 +44,6 @@
|
||||
#include "namespaces.h"
|
||||
#include "imports.h"
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
* Module interfaces *
|
||||
@@ -617,7 +615,7 @@ declare_new_prefix:
|
||||
* - xsltCopyPropList() (*not* anymore)
|
||||
* - xsltShallowCopyElement()
|
||||
* - xsltCopyTreeInternal() (*not* anymore)
|
||||
* - xsltApplyOneTemplateInt() (*not* in the refactored code),
|
||||
* - xsltApplySequenceConstructor() (*not* in the refactored code),
|
||||
* - xsltElement() (*not* anymore)
|
||||
*
|
||||
* Returns a namespace declaration or NULL in case of
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "templates.h"
|
||||
#include "keys.h"
|
||||
#include "pattern.h"
|
||||
#include "documents.h"
|
||||
|
||||
#ifdef WITH_XSLT_DEBUG
|
||||
#define WITH_XSLT_DEBUG_PATTERN
|
||||
@@ -858,7 +859,8 @@ restart:
|
||||
(previous->name != NULL) &&
|
||||
(sibling->name != NULL) &&
|
||||
(previous->name[0] == sibling->name[0]) &&
|
||||
(xmlStrEqual(previous->name, sibling->name))) {
|
||||
(xmlStrEqual(previous->name, sibling->name)))
|
||||
{
|
||||
if ((sel->value2 == NULL) ||
|
||||
((sibling->ns != NULL) &&
|
||||
(xmlStrEqual(sel->value2,
|
||||
@@ -874,11 +876,20 @@ restart:
|
||||
while (sibling != NULL) {
|
||||
if (sibling == previous)
|
||||
break;
|
||||
if ((previous->type == XML_ELEMENT_NODE) &&
|
||||
(previous->name != NULL) &&
|
||||
(sibling->name != NULL) &&
|
||||
(previous->name[0] == sibling->name[0]) &&
|
||||
(xmlStrEqual(previous->name, sibling->name)))
|
||||
{
|
||||
if ((sel->value2 == NULL) ||
|
||||
((sibling->ns != NULL) &&
|
||||
(xmlStrEqual(sel->value2,
|
||||
sibling->ns->href))))
|
||||
{
|
||||
indx--;
|
||||
}
|
||||
}
|
||||
sibling = sibling->next;
|
||||
}
|
||||
}
|
||||
@@ -2211,17 +2222,34 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
|
||||
|
||||
#ifdef XSLT_REFACTORED_KEYCOMP
|
||||
static int
|
||||
xsltComputeAllKeys(xsltTransformContextPtr ctxt,
|
||||
xsltDocumentPtr document)
|
||||
xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode)
|
||||
{
|
||||
xsltStylesheetPtr style, style2;
|
||||
xsltKeyDefPtr keyd, keyd2;
|
||||
xsltKeyTablePtr table;
|
||||
|
||||
if ((ctxt == NULL) || (document == NULL))
|
||||
if ((ctxt == NULL) || (contextNode == NULL)) {
|
||||
xsltTransformError(ctxt, NULL, ctxt->inst,
|
||||
"Internal error in xsltComputeAllKeys(): "
|
||||
"Bad arguments.\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (document->nbKeysComputed == ctxt->nbKeys)
|
||||
if (ctxt->document == NULL) {
|
||||
/*
|
||||
* The document info will only be NULL if we have a RTF.
|
||||
*/
|
||||
if (contextNode->doc->_private != NULL)
|
||||
goto doc_info_mismatch;
|
||||
/*
|
||||
* On-demand creation of the document info (needed for keys).
|
||||
*/
|
||||
ctxt->document = xsltNewDocument(ctxt, contextNode->doc);
|
||||
if (ctxt->document == NULL)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
|
||||
return(0);
|
||||
/*
|
||||
* TODO: This could be further optimized
|
||||
@@ -2234,7 +2262,7 @@ xsltComputeAllKeys(xsltTransformContextPtr ctxt,
|
||||
* Check if keys with this QName have been already
|
||||
* computed.
|
||||
*/
|
||||
table = (xsltKeyTablePtr) document->keys;
|
||||
table = (xsltKeyTablePtr) ctxt->document->keys;
|
||||
while (table) {
|
||||
if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) &&
|
||||
xmlStrEqual(keyd->name, table->name) &&
|
||||
@@ -2257,8 +2285,8 @@ xsltComputeAllKeys(xsltTransformContextPtr ctxt,
|
||||
xmlStrEqual(keyd2->name, keyd->name) &&
|
||||
xmlStrEqual(keyd2->nameURI, keyd->nameURI))
|
||||
{
|
||||
xsltInitCtxtKey(ctxt, document, keyd2);
|
||||
if (document->nbKeysComputed == ctxt->nbKeys)
|
||||
xsltInitCtxtKey(ctxt, ctxt->document, keyd2);
|
||||
if (ctxt->document->nbKeysComputed == ctxt->nbKeys)
|
||||
return(0);
|
||||
}
|
||||
keyd2 = keyd2->next;
|
||||
@@ -2271,6 +2299,14 @@ xsltComputeAllKeys(xsltTransformContextPtr ctxt,
|
||||
style = xsltNextImport(style);
|
||||
}
|
||||
return(0);
|
||||
|
||||
doc_info_mismatch:
|
||||
xsltTransformError(ctxt, NULL, ctxt->inst,
|
||||
"Internal error in xsltComputeAllKeys(): "
|
||||
"The context's document info doesn't match the "
|
||||
"document info of the current result tree.\n");
|
||||
ctxt->state = XSLT_STATE_STOPPED;
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2287,7 +2323,8 @@ xsltComputeAllKeys(xsltTransformContextPtr ctxt,
|
||||
*/
|
||||
xsltTemplatePtr
|
||||
xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
||||
xsltStylesheetPtr style) {
|
||||
xsltStylesheetPtr style)
|
||||
{
|
||||
xsltStylesheetPtr curstyle;
|
||||
xsltTemplatePtr ret = NULL;
|
||||
const xmlChar *name = NULL;
|
||||
@@ -2478,14 +2515,16 @@ keyed_match:
|
||||
}
|
||||
#ifdef XSLT_REFACTORED_KEYCOMP
|
||||
else if (ctxt->hasTemplKeyPatterns &&
|
||||
(ctxt->document->nbKeysComputed < ctxt->nbKeys))
|
||||
((ctxt->document == NULL) ||
|
||||
(ctxt->document->nbKeysComputed < ctxt->nbKeys)))
|
||||
{
|
||||
/*
|
||||
* Compute all remaining keys for this document.
|
||||
*
|
||||
* REVISIT TODO: I think this could be further optimized.
|
||||
*/
|
||||
xsltComputeAllKeys(ctxt, ctxt->document);
|
||||
if (xsltComputeAllKeys(ctxt, node) == -1)
|
||||
goto error;
|
||||
|
||||
switch (node->type) {
|
||||
case XML_ELEMENT_NODE:
|
||||
@@ -2519,6 +2558,8 @@ keyed_match:
|
||||
*/
|
||||
curstyle = xsltNextImport(curstyle);
|
||||
}
|
||||
|
||||
error:
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
@@ -1007,7 +1007,7 @@ xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
NULL, &comp->has_name);
|
||||
if (! comp->has_name) {
|
||||
xsltTransformError(NULL, style, inst,
|
||||
"xsl:attribute: The attribute 'name' is missing.\n");
|
||||
"XSLT-attribute: The attribute 'name' is missing.\n");
|
||||
style->errors++;
|
||||
return;
|
||||
}
|
||||
@@ -1303,6 +1303,9 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
} else {
|
||||
const xmlChar *URI;
|
||||
|
||||
/*
|
||||
* @prop will be in the string dict afterwards, @URI not.
|
||||
*/
|
||||
URI = xsltGetQNameURI2(style, inst, &prop);
|
||||
if (prop == NULL) {
|
||||
if (style != NULL) style->errors++;
|
||||
@@ -1310,7 +1313,12 @@ xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
comp->name = prop;
|
||||
comp->has_name = 1;
|
||||
if (URI != NULL) {
|
||||
comp->ns = xmlStrdup(URI);
|
||||
/*
|
||||
* Fixes bug #308441: Put the ns-name in the dict
|
||||
* in order to pointer compare names during XPath's
|
||||
* variable lookup.
|
||||
*/
|
||||
comp->ns = xmlDictLookup(style->dict, URI, -1);
|
||||
comp->has_ns = 1;
|
||||
} else {
|
||||
comp->has_ns = 0;
|
||||
@@ -1530,7 +1538,7 @@ xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
comp->name = prop;
|
||||
comp->has_name = 1;
|
||||
if (URI != NULL) {
|
||||
comp->ns = URI;
|
||||
comp->ns = xmlDictLookup(style->dict, URI, -1);
|
||||
comp->has_ns = 1;
|
||||
} else {
|
||||
comp->has_ns = 0;
|
||||
@@ -1791,6 +1799,7 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
xsltStylePreCompPtr comp;
|
||||
#endif
|
||||
const xmlChar *prop;
|
||||
const xmlChar *URI;
|
||||
|
||||
if ((style == NULL) || (inst == NULL))
|
||||
return;
|
||||
@@ -1804,51 +1813,65 @@ xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
|
||||
if (comp == NULL)
|
||||
return;
|
||||
|
||||
inst->psvi = comp;
|
||||
comp->inst = inst;
|
||||
|
||||
/*
|
||||
* The full template resolution can be done statically
|
||||
*/
|
||||
|
||||
/*
|
||||
* Attribute "name".
|
||||
*/
|
||||
prop = xsltGetCNsProp(style, inst, (const xmlChar *)"name", XSLT_NAMESPACE);
|
||||
if (prop == NULL) {
|
||||
xsltTransformError(NULL, style, inst,
|
||||
"xsl:variable : name is missing\n");
|
||||
if (style != NULL) style->errors++;
|
||||
} else {
|
||||
const xmlChar *URI;
|
||||
|
||||
"XSLT-variable: The attribute 'name' is missing.\n");
|
||||
style->errors++;
|
||||
goto error;
|
||||
}
|
||||
if (xmlValidateQName(prop, 0)) {
|
||||
xsltTransformError(NULL, style, inst,
|
||||
"XSLT-variable: The value '%s' of the attribute 'name' is "
|
||||
"not a valid QName.\n", prop);
|
||||
style->errors++;
|
||||
goto error;
|
||||
}
|
||||
URI = xsltGetQNameURI2(style, inst, &prop);
|
||||
if (prop == NULL) {
|
||||
if (style != NULL) style->errors++;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
comp->name = prop;
|
||||
comp->has_name = 1;
|
||||
|
||||
if (URI != NULL) {
|
||||
comp->ns = xmlDictLookup(style->dict, URI, -1);
|
||||
comp->has_ns = 1;
|
||||
} else {
|
||||
comp->has_ns = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attribute "select".
|
||||
*/
|
||||
comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select",
|
||||
XSLT_NAMESPACE);
|
||||
if (comp->select != NULL) {
|
||||
comp->comp = xsltXPathCompile(style, comp->select);
|
||||
if (comp->comp == NULL) {
|
||||
xsltTransformError(NULL, style, inst,
|
||||
"xsl:variable : could not compile select expression '%s'\n",
|
||||
"XSLT-variable: Failed to compile the XPath expression '%s'.\n",
|
||||
comp->select);
|
||||
if (style != NULL) style->errors++;
|
||||
style->errors++;
|
||||
}
|
||||
if (inst->children != NULL) {
|
||||
xsltTransformError(NULL, style, inst,
|
||||
"xsl:variable : content should be empty since select is present \n");
|
||||
if (style != NULL) style->warnings++;
|
||||
"XSLT-variable: The must be no child nodes, since the "
|
||||
"attribute 'select' was specified.\n");
|
||||
style->errors++;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1900,7 +1923,7 @@ xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) {
|
||||
comp->name = prop;
|
||||
comp->has_name = 1;
|
||||
if (URI != NULL) {
|
||||
comp->ns = xmlStrdup(URI);
|
||||
comp->ns = xmlDictLookup(style->dict, URI, -1);
|
||||
comp->has_ns = 1;
|
||||
} else {
|
||||
comp->has_ns = 0;
|
||||
|
@@ -180,28 +180,28 @@ xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) {
|
||||
/**
|
||||
* xsltEvalTemplateString:
|
||||
* @ctxt: the XSLT transformation context
|
||||
* @currentNode: the current node in the source tree
|
||||
* @parent: the content parent
|
||||
* @contextNode: the current node in the source tree
|
||||
* @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction)
|
||||
*
|
||||
* Evaluate a template string value, i.e. the parent list is interpreted
|
||||
* as template content and the resulting tree string value is returned
|
||||
* This is needed for example by xsl:comment and xsl:processing-instruction
|
||||
* Processes the sequence constructor of the given instruction on
|
||||
* @contextNode and converts the resulting tree to a string.
|
||||
* This is needed by e.g. xsl:comment and xsl:processing-instruction.
|
||||
*
|
||||
* Returns the computed string value or NULL, must be deallocated by the
|
||||
* caller.
|
||||
* Returns the computed string value or NULL; it's up to the caller to
|
||||
* free the result.
|
||||
*/
|
||||
xmlChar *
|
||||
xsltEvalTemplateString(xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr currentNode,
|
||||
xmlNodePtr parent)
|
||||
xmlNodePtr contextNode,
|
||||
xmlNodePtr inst)
|
||||
{
|
||||
xmlNodePtr oldInsert, insert = NULL;
|
||||
xmlChar *ret;
|
||||
|
||||
if ((ctxt == NULL) || (currentNode == NULL) || (parent == NULL))
|
||||
if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL))
|
||||
return(NULL);
|
||||
|
||||
if (parent->children == NULL)
|
||||
if (inst->children == NULL)
|
||||
return(NULL);
|
||||
|
||||
/*
|
||||
@@ -213,14 +213,16 @@ xsltEvalTemplateString(xsltTransformContextPtr ctxt,
|
||||
insert = xmlNewDocNode(ctxt->output, NULL,
|
||||
(const xmlChar *)"fake", NULL);
|
||||
if (insert == NULL) {
|
||||
xsltTransformError(ctxt, NULL, currentNode,
|
||||
xsltTransformError(ctxt, NULL, contextNode,
|
||||
"Failed to create temporary node\n");
|
||||
return(NULL);
|
||||
}
|
||||
oldInsert = ctxt->insert;
|
||||
ctxt->insert = insert;
|
||||
/* OPTIMIZE TODO: if parent->children consists only of text-nodes. */
|
||||
xsltApplyOneTemplate(ctxt, currentNode, parent->children, NULL, NULL);
|
||||
/*
|
||||
* OPTIMIZE TODO: if inst->children consists only of text-nodes.
|
||||
*/
|
||||
xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL);
|
||||
|
||||
ctxt->insert = oldInsert;
|
||||
|
||||
@@ -603,7 +605,7 @@ xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target,
|
||||
* Copies all non XSLT-attributes over to the @target element
|
||||
* and evaluates Attribute Value Templates.
|
||||
*
|
||||
* Called by xsltApplyOneTemplateInt() (transform.c).
|
||||
* Called by xsltApplySequenceConstructor() (transform.c).
|
||||
*
|
||||
* Returns a new list of attribute nodes, or NULL in case of error.
|
||||
* (Don't assign the result to @target->properties; if
|
||||
|
@@ -27,8 +27,8 @@ XSLTPUBFUN int XSLTCALL
|
||||
int nsNr);
|
||||
XSLTPUBFUN xmlChar * XSLTCALL
|
||||
xsltEvalTemplateString (xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr node,
|
||||
xmlNodePtr parent);
|
||||
xmlNodePtr contextNode,
|
||||
xmlNodePtr inst);
|
||||
XSLTPUBFUN xmlChar * XSLTCALL
|
||||
xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt,
|
||||
xmlNodePtr node,
|
||||
|
2546
libxslt/transform.c
2546
libxslt/transform.c
File diff suppressed because it is too large
Load Diff
1274
libxslt/variables.c
1274
libxslt/variables.c
File diff suppressed because it is too large
Load Diff
324
libxslt/xslt.c
324
libxslt/xslt.c
@@ -485,6 +485,24 @@ xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt,
|
||||
}
|
||||
#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:
|
||||
*
|
||||
@@ -523,6 +541,9 @@ xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt)
|
||||
if (cctxt->nsAliases != NULL)
|
||||
xsltFreeNsAliasList(cctxt->nsAliases);
|
||||
|
||||
if (cctxt->ivars)
|
||||
xsltCompilerVarInfoFree(cctxt);
|
||||
|
||||
xmlFree(cctxt);
|
||||
}
|
||||
|
||||
@@ -1024,16 +1045,6 @@ xsltGetInheritedNsList(xsltStylesheetPtr style,
|
||||
int maxns = 10;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* TODO: This will gather the ns-decls of elements even if
|
||||
* outside xsl:stylesheet. Example:
|
||||
* <doc xmlns:foo="urn:test:foo">
|
||||
* <xsl:stylesheet ...
|
||||
* </doc>
|
||||
* Will have foo="urn:test:foo" in the list.
|
||||
* Is this OK?
|
||||
*/
|
||||
|
||||
if ((style == NULL) || (template == NULL) || (node == NULL) ||
|
||||
(template->inheritedNsNr != 0) || (template->inheritedNs != NULL))
|
||||
return(0);
|
||||
@@ -2027,6 +2038,63 @@ xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
|
||||
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.
|
||||
*/
|
||||
@@ -2043,6 +2111,8 @@ xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
|
||||
if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j]))
|
||||
goto skip_ns;
|
||||
}
|
||||
|
||||
add_effective_ns:
|
||||
/*
|
||||
* OPTIMIZE TODO: This information may not be needed.
|
||||
*/
|
||||
@@ -2058,43 +2128,7 @@ xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt,
|
||||
} while (tmpns != NULL);
|
||||
} else
|
||||
holdByElem = 0;
|
||||
/*
|
||||
* Apply namespace aliasing
|
||||
* ------------------------
|
||||
*
|
||||
* 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 = cctxt->nsAliases;
|
||||
do {
|
||||
/*
|
||||
* TODO: What to do with xmlns="" ?
|
||||
*/
|
||||
if ((alias->literalNs != NULL) &&
|
||||
(xmlStrEqual(alias->literalNs->href, ns->href)))
|
||||
{
|
||||
/*
|
||||
* Recognized as an namespace alias; convert it to
|
||||
* the target namespace.
|
||||
*/
|
||||
if (alias->targetNs != NULL)
|
||||
ns = alias->literalNs;
|
||||
else {
|
||||
/*
|
||||
* The target is the NULL namespace.
|
||||
*/
|
||||
goto skip_ns;
|
||||
}
|
||||
break;
|
||||
}
|
||||
alias = alias->next;
|
||||
} while (alias != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add the effective namespace declaration.
|
||||
@@ -2181,6 +2215,69 @@ xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt,
|
||||
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:
|
||||
*
|
||||
@@ -2316,6 +2413,12 @@ xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
||||
"xsltCompilerNodePop: Depth mismatch.\n");
|
||||
goto mismatch;
|
||||
}
|
||||
/*
|
||||
* Pop information of variables.
|
||||
*/
|
||||
if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth))
|
||||
xsltCompilerVarInfoPop(cctxt);
|
||||
|
||||
cctxt->depth--;
|
||||
cctxt->inode = cctxt->inode->prev;
|
||||
if (cctxt->inode != NULL)
|
||||
@@ -2421,7 +2524,7 @@ xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node)
|
||||
break;
|
||||
}
|
||||
if (i >= nsi->totalNumber) {
|
||||
if (nsi->totalNumber >= maxns) {
|
||||
if (nsi->totalNumber +1 >= maxns) {
|
||||
maxns *= 2;
|
||||
nsi->list =
|
||||
(xmlNsPtr *) xmlRealloc(nsi->list,
|
||||
@@ -3684,6 +3787,17 @@ xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt,
|
||||
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)
|
||||
{
|
||||
@@ -3718,12 +3832,16 @@ xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
|
||||
cctxt->inode->inScopeNs =
|
||||
xsltCompilerBuildInScopeNsList(cctxt, elem);
|
||||
/*
|
||||
* xsltStylePreCompute(): Precompute the XSLT-instruction.
|
||||
* xsltStylePreCompute():
|
||||
* This will compile the information found on the current
|
||||
* element's attributes. NOTE that this won't process the
|
||||
* children of the current element.
|
||||
* children of the instruction.
|
||||
*/
|
||||
xsltStylePreCompute(cctxt->style, elem);
|
||||
/*
|
||||
* TODO: How to react on errors in xsltStylePreCompute() ?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Validate the content model of the XSLT-element.
|
||||
*/
|
||||
@@ -3777,6 +3895,28 @@ xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
|
||||
/* 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:
|
||||
@@ -3792,6 +3932,28 @@ xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem)
|
||||
/* 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:
|
||||
@@ -3998,9 +4160,30 @@ for_each:
|
||||
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);
|
||||
@@ -4010,6 +4193,16 @@ internal_err:
|
||||
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)
|
||||
{
|
||||
@@ -4033,6 +4226,20 @@ xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt)
|
||||
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)
|
||||
@@ -4053,7 +4260,7 @@ xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
|
||||
xsltTransformError(NULL, cctxt->style, node,
|
||||
"Unknown XSLT element '%s'.\n", node->name);
|
||||
cctxt->style->errors++;
|
||||
return(0);
|
||||
return(1);
|
||||
}
|
||||
/*
|
||||
* Forwards-compatible mode.
|
||||
@@ -4106,6 +4313,7 @@ xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt,
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xsltParseSequenceConstructor:
|
||||
*
|
||||
@@ -4374,10 +4582,12 @@ xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
|
||||
|
||||
if (cur->psvi == NULL) {
|
||||
/*
|
||||
* OLD COMMENT: "Unknown element, maybe registered at the
|
||||
* context level. Mark it for later recognition."
|
||||
* 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 xsltApplyOneTemplateInt() at
|
||||
* ANSWER: It is used in
|
||||
* xsltApplySequenceConstructor() at
|
||||
* transformation-time to look out for extension
|
||||
* registered in the transformation context.
|
||||
*/
|
||||
@@ -4400,7 +4610,7 @@ xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
|
||||
* 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 author *does* set the flag, then we'll assume
|
||||
* 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).
|
||||
@@ -4526,8 +4736,8 @@ xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur)
|
||||
* @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" (or "sequence constructor"
|
||||
* in XSLT 2.0) content model. Since it allows addional xsl:param
|
||||
* 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:
|
||||
|
@@ -27,32 +27,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #define XSLT_DEBUG_PROFILE_CACHE */
|
||||
|
||||
#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \
|
||||
(((n)->type == XML_TEXT_NODE) || \
|
||||
((n)->type == XML_CDATA_SECTION_NODE)))
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
extern const xmlChar *xsltDocFragFake;
|
||||
|
||||
#define XSLT_MARK_RES_TREE_FRAG(n) (n)->psvi = (void *) xsltDocFragFake;
|
||||
|
||||
#define XSLT_IS_RES_TREE_FRAG(n) \
|
||||
((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
|
||||
((n)->psvi == xsltDocFragFake))
|
||||
|
||||
#else
|
||||
|
||||
#define XSLT_MARK_RES_TREE_FRAG(n) \
|
||||
(n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt");
|
||||
|
||||
#define XSLT_IS_RES_TREE_FRAG(n) \
|
||||
((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \
|
||||
((n)->name != NULL) && ((n)->name[0] == ' ') && \
|
||||
xmlStrEqual(BAD_CAST (n)->name, BAD_CAST " fake node libxslt"))
|
||||
|
||||
#endif
|
||||
((n)->name != NULL) && ((n)->name[0] == ' '))
|
||||
|
||||
/**
|
||||
* XSLT_REFACTORED_KEYCOMP:
|
||||
@@ -61,6 +48,14 @@ extern const xmlChar *xsltDocFragFake;
|
||||
*/
|
||||
#define XSLT_REFACTORED_KEYCOMP
|
||||
|
||||
/**
|
||||
* XSLT_FAST_IF:
|
||||
*
|
||||
* Internal define to enable usage of xmlXPathCompiledEvalToBoolean()
|
||||
* for XSLT "tests"; e.g. in <xsl:if test="/foo/bar">
|
||||
*/
|
||||
#define XSLT_FAST_IF
|
||||
|
||||
/**
|
||||
* XSLT_REFACTORED:
|
||||
*
|
||||
@@ -69,10 +64,13 @@ extern const xmlChar *xsltDocFragFake;
|
||||
/* #define XSLT_REFACTORED */
|
||||
/* ==================================================================== */
|
||||
|
||||
#define XSLT_REFACTORED_VARS
|
||||
|
||||
#ifdef XSLT_REFACTORED
|
||||
|
||||
extern const xmlChar *xsltXSLTAttrMarker;
|
||||
|
||||
|
||||
/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */
|
||||
|
||||
/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */
|
||||
@@ -243,6 +241,7 @@ struct _xsltTemplate {
|
||||
/* Profiling informations */
|
||||
int nbCalls; /* the number of time the template was called */
|
||||
unsigned long time; /* the time spent in this template */
|
||||
void *params; /* xsl:param instructions */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -275,7 +274,6 @@ struct _xsltDecimalFormat {
|
||||
*
|
||||
* Data structure associated to a parsed document.
|
||||
*/
|
||||
|
||||
typedef struct _xsltDocument xsltDocument;
|
||||
typedef xsltDocument *xsltDocumentPtr;
|
||||
struct _xsltDocument {
|
||||
@@ -478,6 +476,8 @@ struct _xsltNsListContainer {
|
||||
*
|
||||
* Fields for API compatibility to the structure
|
||||
* _xsltElemPreComp which is used for extension functions.
|
||||
* Note that @next is used for storage; it does not reflect a next
|
||||
* sibling in the tree.
|
||||
* TODO: Evaluate if we really need such a compatibility.
|
||||
*/
|
||||
#define XSLT_ITEM_COMPATIBILITY_FIELDS \
|
||||
@@ -940,9 +940,21 @@ typedef xsltStyleItemVariable *xsltStyleItemVariablePtr;
|
||||
* <!-- Content: template -->
|
||||
* </xsl:param>
|
||||
*/
|
||||
typedef xsltStyleBasicItemVariable xsltStyleItemParam;
|
||||
typedef struct _xsltStyleItemParam xsltStyleItemParam;
|
||||
typedef xsltStyleItemParam *xsltStyleItemParamPtr;
|
||||
|
||||
struct _xsltStyleItemParam {
|
||||
XSLT_ITEM_COMMON_FIELDS
|
||||
|
||||
const xmlChar *select;
|
||||
xmlXPathCompExprPtr comp;
|
||||
|
||||
const xmlChar *name;
|
||||
int has_name;
|
||||
const xmlChar *ns;
|
||||
int has_ns;
|
||||
};
|
||||
|
||||
/**
|
||||
* xsltStyleItemWithParam:
|
||||
*
|
||||
@@ -1167,6 +1179,21 @@ struct _xsltNsList {
|
||||
xmlNsPtr ns;
|
||||
};
|
||||
|
||||
/*
|
||||
* xsltVarInfo:
|
||||
*
|
||||
* Used at compilation time for parameters and variables.
|
||||
*/
|
||||
typedef struct _xsltVarInfo xsltVarInfo;
|
||||
typedef xsltVarInfo *xsltVarInfoPtr;
|
||||
struct _xsltVarInfo {
|
||||
xsltVarInfoPtr next; /* next in the list */
|
||||
xsltVarInfoPtr prev;
|
||||
int depth; /* the depth in the tree */
|
||||
const xmlChar *name;
|
||||
const xmlChar *nsName;
|
||||
};
|
||||
|
||||
#define XSLT_ELEMENT_CATEGORY_XSLT 0
|
||||
#define XSLT_ELEMENT_CATEGORY_EXTENSION 1
|
||||
#define XSLT_ELEMENT_CATEGORY_LRE 2
|
||||
@@ -1194,6 +1221,7 @@ struct _xsltCompilerNodeInfo {
|
||||
xsltPointerListPtr exclResultNs;
|
||||
/* The current extension instruction namespaces */
|
||||
xsltPointerListPtr extElemNs;
|
||||
|
||||
/* The current info for literal result elements. */
|
||||
xsltStyleItemLRElementInfoPtr litResElemInfo;
|
||||
/*
|
||||
@@ -1263,6 +1291,8 @@ struct _xsltCompilerCtxt {
|
||||
xsltStyleItemUknownPtr unknownItem;
|
||||
int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */
|
||||
xsltNsAliasPtr nsAliases;
|
||||
xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */
|
||||
xsltVarInfoPtr ivar; /* topmost local variable/param. */
|
||||
};
|
||||
|
||||
#else /* XSLT_REFACTORED */
|
||||
@@ -1329,6 +1359,10 @@ struct _xsltStylePreComp {
|
||||
|
||||
#endif /* XSLT_REFACTORED */
|
||||
|
||||
|
||||
#define XSLT_VAR_GLOBAL 1<<0
|
||||
#define XSLT_VAR_IN_SELECT 1<<1
|
||||
#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable)
|
||||
/*
|
||||
* The in-memory structure corresponding to an XSLT Variable
|
||||
* or Param.
|
||||
@@ -1342,8 +1376,16 @@ struct _xsltStackElem {
|
||||
const xmlChar *name; /* the local part of the name QName */
|
||||
const xmlChar *nameURI; /* the URI part of the name QName */
|
||||
const xmlChar *select; /* the eval string */
|
||||
xmlNodePtr tree; /* the tree if no eval string or the location */
|
||||
xmlNodePtr tree; /* the sequence constructor if no eval
|
||||
string or the location */
|
||||
xmlXPathObjectPtr value; /* The value if computed */
|
||||
xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0)
|
||||
which are bound to the variable's lifetime. */
|
||||
int level; /* the depth in the tree;
|
||||
-1 if persistent (e.g. a given xsl:with-param) */
|
||||
xsltTransformContextPtr context; /* The transformation context; needed to cache
|
||||
the variables */
|
||||
int flags;
|
||||
};
|
||||
|
||||
#ifdef XSLT_REFACTORED
|
||||
@@ -1537,6 +1579,21 @@ struct _xsltStylesheet {
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct _xsltTransformCache xsltTransformCache;
|
||||
typedef xsltTransformCache *xsltTransformCachePtr;
|
||||
struct _xsltTransformCache {
|
||||
xmlDocPtr RVT;
|
||||
int nbRVT;
|
||||
xsltStackElemPtr stackItems;
|
||||
int nbStackItems;
|
||||
#ifdef XSLT_DEBUG_PROFILE_CACHE
|
||||
int dbgCachedRVTs;
|
||||
int dbgReusedRVTs;
|
||||
int dbgCachedVars;
|
||||
int dbgReusedVars;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* The in-memory structure corresponding to an XSLT Transformation.
|
||||
*/
|
||||
@@ -1579,7 +1636,7 @@ struct _xsltTransformContext {
|
||||
|
||||
xsltDocumentPtr docList; /* the document list */
|
||||
|
||||
xsltDocumentPtr document; /* the current document */
|
||||
xsltDocumentPtr document; /* the current source document; can be NULL if an RTF */
|
||||
xmlNodePtr node; /* the current node being processed */
|
||||
xmlNodeSetPtr nodeList; /* the current node list */
|
||||
/* xmlNodePtr current; the node */
|
||||
@@ -1623,6 +1680,7 @@ struct _xsltTransformContext {
|
||||
|
||||
/*
|
||||
* handling of temporary Result Value Tree
|
||||
* (XSLT 1.0 term: "Result Tree Fragment")
|
||||
*/
|
||||
xmlDocPtr tmpRVT; /* list of RVT without persistance */
|
||||
xmlDocPtr persistRVT; /* list of persistant RVTs */
|
||||
@@ -1647,8 +1705,8 @@ struct _xsltTransformContext {
|
||||
*/
|
||||
xmlDictPtr dict;
|
||||
/*
|
||||
* temporary storage for doc ptr, currently only used for
|
||||
* global var evaluation
|
||||
* The current source doc; one of: the initial source doc, a RTF
|
||||
* or a source doc aquired via the document() function.
|
||||
*/
|
||||
xmlDocPtr tmpDoc;
|
||||
/*
|
||||
@@ -1657,6 +1715,15 @@ struct _xsltTransformContext {
|
||||
int internalized;
|
||||
int nbKeys;
|
||||
int hasTemplKeyPatterns;
|
||||
xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */
|
||||
xmlNodePtr initialContextNode;
|
||||
xmlDocPtr initialContextDoc;
|
||||
xsltTransformCachePtr cache;
|
||||
void *contextVariable; /* the current variable item */
|
||||
xmlDocPtr localRVT; /* list of local tree fragments; will be freed when
|
||||
the instruction which created the fragment
|
||||
exits */
|
||||
xmlDocPtr localRVTBase;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1762,11 +1829,31 @@ XSLTPUBFUN xmlDocPtr XSLTCALL
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltRegisterTmpRVT (xsltTransformContextPtr ctxt,
|
||||
xmlDocPtr RVT);
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltRegisterLocalRVT (xsltTransformContextPtr ctxt,
|
||||
xmlDocPtr RVT);
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltRegisterPersistRVT (xsltTransformContextPtr ctxt,
|
||||
xmlDocPtr RVT);
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltExtensionInstructionResultRegister(
|
||||
xsltTransformContextPtr ctxt,
|
||||
xmlXPathObjectPtr obj);
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltExtensionInstructionResultFinalize(
|
||||
xsltTransformContextPtr ctxt);
|
||||
XSLTPUBFUN void XSLTCALL
|
||||
xsltFreeRVTs (xsltTransformContextPtr ctxt);
|
||||
XSLTPUBFUN void XSLTCALL
|
||||
xsltReleaseRVT (xsltTransformContextPtr ctxt,
|
||||
xmlDocPtr RVT);
|
||||
XSLTPUBFUN int XSLTCALL
|
||||
xsltTransStorageAdd (xsltTransformContextPtr ctxt,
|
||||
void *id,
|
||||
void *data);
|
||||
XSLTPUBFUN void * XSLTCALL
|
||||
xsltTransStorageRemove (xsltTransformContextPtr ctxt,
|
||||
void *id);
|
||||
|
||||
/*
|
||||
* Extra functions for Attribute Value Templates
|
||||
|
@@ -876,9 +876,16 @@ xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
|
||||
qname = xmlStrndup(*name, len);
|
||||
ns = xmlSearchNs(node->doc, node, qname);
|
||||
if (ns == NULL) {
|
||||
if (style) {
|
||||
xsltTransformError(NULL, style, node,
|
||||
"No namespace bound to prefix '%s'.\n",
|
||||
qname);
|
||||
style->errors++;
|
||||
} else {
|
||||
xsltGenericError(xsltGenericErrorContext,
|
||||
"%s : no namespace bound to prefix %s\n",
|
||||
*name, qname);
|
||||
}
|
||||
*name = NULL;
|
||||
xmlFree(qname);
|
||||
return(NULL);
|
||||
|
@@ -72,9 +72,11 @@ extern "C" {
|
||||
(((n) != NULL) && \
|
||||
(((n)->type == XML_ELEMENT_NODE) || \
|
||||
((n)->type == XML_TEXT_NODE) || \
|
||||
((n)->type == XML_CDATA_SECTION_NODE) || \
|
||||
((n)->type == XML_ATTRIBUTE_NODE) || \
|
||||
((n)->type == XML_DOCUMENT_NODE) || \
|
||||
((n)->type == XML_HTML_DOCUMENT_NODE) || \
|
||||
((n)->type == XML_COMMENT_NODE) || \
|
||||
((n)->type == XML_PI_NODE)))
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user