diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | doc/xsltproc.1 | 4 | ||||
-rw-r--r-- | libxslt/preproc.c | 226 | ||||
-rw-r--r-- | libxslt/xslt.c | 17 | ||||
-rw-r--r-- | libxslt/xsltInternals.h | 4 | ||||
-rw-r--r-- | libxslt/xsltwin32config.h | 2 | ||||
-rw-r--r-- | tests/general/bug-89.xsl | 5 |
7 files changed, 240 insertions, 28 deletions
@@ -1,6 +1,14 @@ +Tue Mar 29 15:13:59 CEST 2005 Daniel Veillard <daniel@veillard.com> + + * libxslt/preproc.c libxslt/xslt.c libxslt/xsltInternals.h: + added DTD like checking when compiling stylesheets, closes + bug #160402 and a long term TODO + * tests/general/bug-89.xsl: thos spotted a misconstruct of one + of the test cases where <xsl:when> was not within <xsl:choose> + Mon Mar 21 20:56:43 MST 2005 John Fleck (jfleck@inkstain.net) - * doc/xsltproc.xml, xsltproc.html, xsltproc.1 + * doc/xsltproc.xml, xsltproc.html, xsltproc.1: update documentation to reflect addition of --nodtdattr command line flag. Bug #171098 diff --git a/doc/xsltproc.1 b/doc/xsltproc.1 index 8aaabbd6..460bcc17 100644 --- a/doc/xsltproc.1 +++ b/doc/xsltproc.1 @@ -54,7 +54,7 @@ Output each step taken by xsltproc in processing the stylesheet and the document .TP \fB\-o\fR or \fB\-\-output\fR \fIfile\fR -Direct output to the file named \fIfile\fR\&. For multiple outputs, also known as "chunking", \fB\-o\fR \fBdirectory/\fR directs the output files to a specified directory\&. The directory must already exist\&. +Direct output to the file named \fIfile\fR\&. For multiple outputs, also known as "chunking", \fB\-o\fR \fBdirectory/\fR directs the output files to a specified directory\&. The directory must already exist\&. .TP \fB\-\-timing\fR @@ -110,7 +110,7 @@ Use the SGML catalog specified in \fBSGML_CATALOG_FILES\fR to resolve the locati .TP \fB\-\-xinclude\fR -Process the input document using the Xinclude specification\&. More details on this can be found in the Xinclude specification: http://www\&.w3\&.org/TR/xinclude/: \fIhttp://www.w3.org/TR/xinclude/\fR +Process the input document using the Xinclude specification\&. More details on this can be found in the Xinclude specification: http://www\&.w3\&.org/TR/xinclude/: \fIhttp://www.w3.org/TR/xinclude/\fR .TP \fB\-\-profile\fR or \fB\-\-norman\fR diff --git a/libxslt/preproc.c b/libxslt/preproc.c index a55874dd..e4e69dc6 100644 --- a/libxslt/preproc.c +++ b/libxslt/preproc.c @@ -48,6 +48,158 @@ const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; /************************************************************************ * * + * Grammar checks * + * * + ************************************************************************/ + +/** + * xsltCheckTopLevelElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * @err: raise an error or not + * + * Check that the instruction is instanciated as a top level element. + * + * Returns -1 in case of error, 0 if failed and 1 in case of success + */ +static int +xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) { + xmlNodePtr parent; + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL)) + return(-1); + + parent = inst->parent; + if (parent == NULL) { + if (err) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + } + return(0); + } + if ((parent->ns == NULL) || + ((parent->ns != inst->ns) && + (!xmlStrEqual(parent->ns->href, inst->ns->href))) || + ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) && + (!xmlStrEqual(parent->name, BAD_CAST "transform")))) { + if (err) { + xsltTransformError(NULL, style, inst, + "element %s only allowed as child of stylesheet\n", + inst->name); + style->errors++; + } + return(0); + } + return(1); +} + +/** + * xsltCheckInstructionElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * + * Check that the instruction is instanciated as an instruction element. + */ +static void +xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) { + xmlNodePtr parent; + int has_ext; + + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || + (style->literal_result)) + return; + + has_ext = (style->extInfos != NULL); + + parent = inst->parent; + if (parent == NULL) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + return; + } + while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { + if (((parent->ns == inst->ns) || + ((parent->ns != NULL) && + (xmlStrEqual(parent->ns->href, inst->ns->href)))) && + ((xmlStrEqual(parent->name, BAD_CAST "template")) || + (xmlStrEqual(parent->name, BAD_CAST "param")) || + (xmlStrEqual(parent->name, BAD_CAST "attribute")) || + (xmlStrEqual(parent->name, BAD_CAST "variable")))) { + return; + } + + /* + * if we are within an extension element all bets are off + * about the semantic there e.g. xsl:param within func:function + */ + if ((has_ext) && (parent->ns != NULL) && + (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) + return; + + parent = parent->parent; + } + xsltTransformError(NULL, style, inst, + "element %s only allowed within a template, variable or param\n", + inst->name); + style->errors++; +} + +/** + * xsltCheckParentElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * @allow1: allowed parent1 + * @allow2: allowed parent2 + * + * Check that the instruction is instanciated as the childre of one of the + * possible parents. + */ +static void +xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, + const xmlChar *allow1, const xmlChar *allow2) { + xmlNodePtr parent; + + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || + (style->literal_result)) + return; + + parent = inst->parent; + if (parent == NULL) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + return; + } + if (((parent->ns == inst->ns) || + ((parent->ns != NULL) && + (xmlStrEqual(parent->ns->href, inst->ns->href)))) && + ((xmlStrEqual(parent->name, allow1)) || + (xmlStrEqual(parent->name, allow2)))) { + return; + } + + if (style->extInfos != NULL) { + while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { + /* + * if we are within an extension element all bets are off + * about the semantic there e.g. xsl:param within func:function + */ + if ((parent->ns != NULL) && + (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) + return; + + parent = parent->parent; + } + } + xsltTransformError(NULL, style, inst, + "element %s is not allowed within that context\n", + inst->name); + style->errors++; +} + +/************************************************************************ + * * * handling of precomputed data * * * ************************************************************************/ @@ -1192,91 +1344,129 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { xsltStylePreCompPtr cur; if (IS_XSLT_NAME(inst, "apply-templates")) { + xsltCheckInstructionElement(style, inst); xsltApplyTemplatesComp(style, inst); } else if (IS_XSLT_NAME(inst, "with-param")) { + xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", + BAD_CAST "call-template"); xsltWithParamComp(style, inst); } else if (IS_XSLT_NAME(inst, "value-of")) { + xsltCheckInstructionElement(style, inst); xsltValueOfComp(style, inst); } else if (IS_XSLT_NAME(inst, "copy")) { + xsltCheckInstructionElement(style, inst); xsltCopyComp(style, inst); } else if (IS_XSLT_NAME(inst, "copy-of")) { + xsltCheckInstructionElement(style, inst); xsltCopyOfComp(style, inst); } else if (IS_XSLT_NAME(inst, "if")) { + xsltCheckInstructionElement(style, inst); xsltIfComp(style, inst); } else if (IS_XSLT_NAME(inst, "when")) { + xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); xsltWhenComp(style, inst); } else if (IS_XSLT_NAME(inst, "choose")) { + xsltCheckInstructionElement(style, inst); xsltChooseComp(style, inst); } else if (IS_XSLT_NAME(inst, "for-each")) { + xsltCheckInstructionElement(style, inst); xsltForEachComp(style, inst); } else if (IS_XSLT_NAME(inst, "apply-imports")) { + xsltCheckInstructionElement(style, inst); xsltApplyImportsComp(style, inst); } else if (IS_XSLT_NAME(inst, "attribute")) { + xmlNodePtr parent = inst->parent; + + if ((parent == NULL) || (parent->ns == NULL) || + ((parent->ns != inst->ns) && + (!xmlStrEqual(parent->ns->href, inst->ns->href))) || + (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) { + xsltCheckInstructionElement(style, inst); + } xsltAttributeComp(style, inst); } else if (IS_XSLT_NAME(inst, "element")) { + xsltCheckInstructionElement(style, inst); xsltElementComp(style, inst); } else if (IS_XSLT_NAME(inst, "text")) { + xsltCheckInstructionElement(style, inst); xsltTextComp(style, inst); } else if (IS_XSLT_NAME(inst, "sort")) { + xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", + BAD_CAST "for-each"); xsltSortComp(style, inst); } else if (IS_XSLT_NAME(inst, "comment")) { + xsltCheckInstructionElement(style, inst); xsltCommentComp(style, inst); } else if (IS_XSLT_NAME(inst, "number")) { + xsltCheckInstructionElement(style, inst); xsltNumberComp(style, inst); } else if (IS_XSLT_NAME(inst, "processing-instruction")) { + xsltCheckInstructionElement(style, inst); xsltProcessingInstructionComp(style, inst); } else if (IS_XSLT_NAME(inst, "call-template")) { + xsltCheckInstructionElement(style, inst); xsltCallTemplateComp(style, inst); } else if (IS_XSLT_NAME(inst, "param")) { + if (xsltCheckTopLevelElement(style, inst, 0) == 0) + xsltCheckInstructionElement(style, inst); xsltParamComp(style, inst); } else if (IS_XSLT_NAME(inst, "variable")) { + if (xsltCheckTopLevelElement(style, inst, 0) == 0) + xsltCheckInstructionElement(style, inst); xsltVariableComp(style, inst); } else if (IS_XSLT_NAME(inst, "otherwise")) { - /* no computation needed */ + xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); + xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "template")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "output")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "preserve-space")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "strip-space")) { - /* no computation needed */ - return; - } else if (IS_XSLT_NAME(inst, "stylesheet")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; - } else if (IS_XSLT_NAME(inst, "transform")) { - /* no computation needed */ + } else if ((IS_XSLT_NAME(inst, "stylesheet")) || + (IS_XSLT_NAME(inst, "transform"))) { + xmlNodePtr parent = inst->parent; + + if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) { + xsltTransformError(NULL, style, inst, + "element %s only allowed only as root element\n", + inst->name); + style->errors++; + } return; } else if (IS_XSLT_NAME(inst, "key")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "message")) { - /* no computation needed */ + xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "attribute-set")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "namespace-alias")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "include")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "import")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "decimal-format")) { - /* no computation needed */ + xsltCheckTopLevelElement(style, inst, 1); return; } else if (IS_XSLT_NAME(inst, "fallback")) { - /* no computation needed */ + xsltCheckInstructionElement(style, inst); return; } else if (IS_XSLT_NAME(inst, "document")) { + xsltCheckInstructionElement(style, inst); inst->psvi = (void *) xsltDocumentComp(style, inst, (xsltTransformFunction) xsltDocumentElem); } else { diff --git a/libxslt/xslt.c b/libxslt/xslt.c index cae7a184..9be9533b 100644 --- a/libxslt/xslt.c +++ b/libxslt/xslt.c @@ -375,6 +375,7 @@ xsltNewStylesheet(void) { cur->extInfos = NULL; cur->extrasNr = 0; cur->internalized = 1; + cur->literal_result = 0; cur->dict = xmlDictCreate(); #ifdef WITH_XSLT_DEBUG xsltGenericDebug(xsltGenericDebugContext, @@ -1901,8 +1902,6 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { xmlFree(prop); } - xsltParseStylesheetExtPrefix(style, top); - cur = top->children; /* @@ -2048,9 +2047,6 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { return(NULL); } xsltParseStylesheetExcludePrefix(ret, cur); - if (!ret->nopreproc) - xsltPrecomputeStylesheet(ret, cur); - if ((IS_XSLT_ELEM(cur)) && ((IS_XSLT_NAME(cur, "stylesheet")) || (IS_XSLT_NAME(cur, "transform")))) { @@ -2058,6 +2054,16 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { xsltGenericDebug(xsltGenericDebugContext, "xsltParseStylesheetProcess : found stylesheet\n"); #endif + ret->literal_result = 0; + + xsltParseStylesheetExtPrefix(ret, cur); + } else { + ret->literal_result = 1; + } + if (!ret->nopreproc) + xsltPrecomputeStylesheet(ret, cur); + + if (ret->literal_result == 0) { xsltParseStylesheetTop(ret, cur); } else { @@ -2105,6 +2111,7 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { template->elem = (xmlNodePtr) doc; template->content = doc->children; xsltAddTemplate(ret, template, NULL, NULL); + ret->literal_result = 1; } return(ret); diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index 807e2a67..193316f6 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -447,6 +447,10 @@ struct _xsltStylesheet { * all document text strings were internalized */ int internalized; + /* + * Literal Result Element as Stylesheet c.f. section 2.3 + */ + int literal_result; }; /* diff --git a/libxslt/xsltwin32config.h b/libxslt/xsltwin32config.h index 5369727d..f4864cde 100644 --- a/libxslt/xsltwin32config.h +++ b/libxslt/xsltwin32config.h @@ -44,7 +44,7 @@ extern "C" { * * extra version information, used to show a CVS compilation */ -#define LIBXSLT_VERSION_EXTRA "-CVS998" +#define LIBXSLT_VERSION_EXTRA "-CVS999" /** * WITH_XSLT_DEBUG: diff --git a/tests/general/bug-89.xsl b/tests/general/bug-89.xsl index 502fb7a4..4bf4ca16 100644 --- a/tests/general/bug-89.xsl +++ b/tests/general/bug-89.xsl @@ -44,9 +44,12 @@ la valeur nulle --> </xsl:call-template> </xsl:when> <xsl:when test="$action='repl'"> +<xsl:choose> <xsl:when test="$action='del'"> <xsl:call-template name="del"/> -</xsl:when> <xsl:call-template name="add"> +</xsl:when> +</xsl:choose> +<xsl:call-template name="add"> <xsl:with-param name="type">toto</xsl:with-param> </xsl:call-template> </xsl:when> </xsl:choose> |