summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--doc/xsltproc.14
-rw-r--r--libxslt/preproc.c226
-rw-r--r--libxslt/xslt.c17
-rw-r--r--libxslt/xsltInternals.h4
-rw-r--r--libxslt/xsltwin32config.h2
-rw-r--r--tests/general/bug-89.xsl5
7 files changed, 240 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index 51dd45a9..465a548a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>