1
0
mirror of https://gitlab.gnome.org/GNOME/libxslt synced 2025-07-29 15:41:13 +03:00

added DTD like checking when compiling stylesheets, closes bug #160402 and

* 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>
Daniel
This commit is contained in:
Daniel Veillard
2005-03-29 13:16:06 +00:00
parent 9b631cb80d
commit 7cbb21dabd
7 changed files with 240 additions and 28 deletions

View File

@ -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) 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 update documentation to reflect addition of --nodtdattr
command line flag. Bug #171098 command line flag. Bug #171098

View File

@ -54,7 +54,7 @@ Output each step taken by xsltproc in processing the stylesheet and the document
.TP .TP
\fB\-o\fR or \fB\-\-output\fR \fIfile\fR \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 .TP
\fB\-\-timing\fR \fB\-\-timing\fR
@ -110,7 +110,7 @@ Use the SGML catalog specified in \fBSGML_CATALOG_FILES\fR to resolve the locati
.TP .TP
\fB\-\-xinclude\fR \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 .TP
\fB\-\-profile\fR or \fB\-\-norman\fR \fB\-\-profile\fR or \fB\-\-norman\fR

View File

@ -46,6 +46,158 @@
const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; 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 * * handling of precomputed data *
@ -1192,91 +1344,129 @@ xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) {
xsltStylePreCompPtr cur; xsltStylePreCompPtr cur;
if (IS_XSLT_NAME(inst, "apply-templates")) { if (IS_XSLT_NAME(inst, "apply-templates")) {
xsltCheckInstructionElement(style, inst);
xsltApplyTemplatesComp(style, inst); xsltApplyTemplatesComp(style, inst);
} else if (IS_XSLT_NAME(inst, "with-param")) { } else if (IS_XSLT_NAME(inst, "with-param")) {
xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
BAD_CAST "call-template");
xsltWithParamComp(style, inst); xsltWithParamComp(style, inst);
} else if (IS_XSLT_NAME(inst, "value-of")) { } else if (IS_XSLT_NAME(inst, "value-of")) {
xsltCheckInstructionElement(style, inst);
xsltValueOfComp(style, inst); xsltValueOfComp(style, inst);
} else if (IS_XSLT_NAME(inst, "copy")) { } else if (IS_XSLT_NAME(inst, "copy")) {
xsltCheckInstructionElement(style, inst);
xsltCopyComp(style, inst); xsltCopyComp(style, inst);
} else if (IS_XSLT_NAME(inst, "copy-of")) { } else if (IS_XSLT_NAME(inst, "copy-of")) {
xsltCheckInstructionElement(style, inst);
xsltCopyOfComp(style, inst); xsltCopyOfComp(style, inst);
} else if (IS_XSLT_NAME(inst, "if")) { } else if (IS_XSLT_NAME(inst, "if")) {
xsltCheckInstructionElement(style, inst);
xsltIfComp(style, inst); xsltIfComp(style, inst);
} else if (IS_XSLT_NAME(inst, "when")) { } else if (IS_XSLT_NAME(inst, "when")) {
xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
xsltWhenComp(style, inst); xsltWhenComp(style, inst);
} else if (IS_XSLT_NAME(inst, "choose")) { } else if (IS_XSLT_NAME(inst, "choose")) {
xsltCheckInstructionElement(style, inst);
xsltChooseComp(style, inst); xsltChooseComp(style, inst);
} else if (IS_XSLT_NAME(inst, "for-each")) { } else if (IS_XSLT_NAME(inst, "for-each")) {
xsltCheckInstructionElement(style, inst);
xsltForEachComp(style, inst); xsltForEachComp(style, inst);
} else if (IS_XSLT_NAME(inst, "apply-imports")) { } else if (IS_XSLT_NAME(inst, "apply-imports")) {
xsltCheckInstructionElement(style, inst);
xsltApplyImportsComp(style, inst); xsltApplyImportsComp(style, inst);
} else if (IS_XSLT_NAME(inst, "attribute")) { } 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); xsltAttributeComp(style, inst);
} else if (IS_XSLT_NAME(inst, "element")) { } else if (IS_XSLT_NAME(inst, "element")) {
xsltCheckInstructionElement(style, inst);
xsltElementComp(style, inst); xsltElementComp(style, inst);
} else if (IS_XSLT_NAME(inst, "text")) { } else if (IS_XSLT_NAME(inst, "text")) {
xsltCheckInstructionElement(style, inst);
xsltTextComp(style, inst); xsltTextComp(style, inst);
} else if (IS_XSLT_NAME(inst, "sort")) { } else if (IS_XSLT_NAME(inst, "sort")) {
xsltCheckParentElement(style, inst, BAD_CAST "apply-templates",
BAD_CAST "for-each");
xsltSortComp(style, inst); xsltSortComp(style, inst);
} else if (IS_XSLT_NAME(inst, "comment")) { } else if (IS_XSLT_NAME(inst, "comment")) {
xsltCheckInstructionElement(style, inst);
xsltCommentComp(style, inst); xsltCommentComp(style, inst);
} else if (IS_XSLT_NAME(inst, "number")) { } else if (IS_XSLT_NAME(inst, "number")) {
xsltCheckInstructionElement(style, inst);
xsltNumberComp(style, inst); xsltNumberComp(style, inst);
} else if (IS_XSLT_NAME(inst, "processing-instruction")) { } else if (IS_XSLT_NAME(inst, "processing-instruction")) {
xsltCheckInstructionElement(style, inst);
xsltProcessingInstructionComp(style, inst); xsltProcessingInstructionComp(style, inst);
} else if (IS_XSLT_NAME(inst, "call-template")) { } else if (IS_XSLT_NAME(inst, "call-template")) {
xsltCheckInstructionElement(style, inst);
xsltCallTemplateComp(style, inst); xsltCallTemplateComp(style, inst);
} else if (IS_XSLT_NAME(inst, "param")) { } else if (IS_XSLT_NAME(inst, "param")) {
if (xsltCheckTopLevelElement(style, inst, 0) == 0)
xsltCheckInstructionElement(style, inst);
xsltParamComp(style, inst); xsltParamComp(style, inst);
} else if (IS_XSLT_NAME(inst, "variable")) { } else if (IS_XSLT_NAME(inst, "variable")) {
if (xsltCheckTopLevelElement(style, inst, 0) == 0)
xsltCheckInstructionElement(style, inst);
xsltVariableComp(style, inst); xsltVariableComp(style, inst);
} else if (IS_XSLT_NAME(inst, "otherwise")) { } else if (IS_XSLT_NAME(inst, "otherwise")) {
/* no computation needed */ xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL);
xsltCheckInstructionElement(style, inst);
return; return;
} else if (IS_XSLT_NAME(inst, "template")) { } else if (IS_XSLT_NAME(inst, "template")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "output")) { } else if (IS_XSLT_NAME(inst, "output")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "preserve-space")) { } else if (IS_XSLT_NAME(inst, "preserve-space")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "strip-space")) { } else if (IS_XSLT_NAME(inst, "strip-space")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "stylesheet")) { } else if ((IS_XSLT_NAME(inst, "stylesheet")) ||
/* no computation needed */ (IS_XSLT_NAME(inst, "transform"))) {
return; xmlNodePtr parent = inst->parent;
} else if (IS_XSLT_NAME(inst, "transform")) {
/* no computation needed */ 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; return;
} else if (IS_XSLT_NAME(inst, "key")) { } else if (IS_XSLT_NAME(inst, "key")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "message")) { } else if (IS_XSLT_NAME(inst, "message")) {
/* no computation needed */ xsltCheckInstructionElement(style, inst);
return; return;
} else if (IS_XSLT_NAME(inst, "attribute-set")) { } else if (IS_XSLT_NAME(inst, "attribute-set")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "namespace-alias")) { } else if (IS_XSLT_NAME(inst, "namespace-alias")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "include")) { } else if (IS_XSLT_NAME(inst, "include")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "import")) { } else if (IS_XSLT_NAME(inst, "import")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "decimal-format")) { } else if (IS_XSLT_NAME(inst, "decimal-format")) {
/* no computation needed */ xsltCheckTopLevelElement(style, inst, 1);
return; return;
} else if (IS_XSLT_NAME(inst, "fallback")) { } else if (IS_XSLT_NAME(inst, "fallback")) {
/* no computation needed */ xsltCheckInstructionElement(style, inst);
return; return;
} else if (IS_XSLT_NAME(inst, "document")) { } else if (IS_XSLT_NAME(inst, "document")) {
xsltCheckInstructionElement(style, inst);
inst->psvi = (void *) xsltDocumentComp(style, inst, inst->psvi = (void *) xsltDocumentComp(style, inst,
(xsltTransformFunction) xsltDocumentElem); (xsltTransformFunction) xsltDocumentElem);
} else { } else {

View File

@ -375,6 +375,7 @@ xsltNewStylesheet(void) {
cur->extInfos = NULL; cur->extInfos = NULL;
cur->extrasNr = 0; cur->extrasNr = 0;
cur->internalized = 1; cur->internalized = 1;
cur->literal_result = 0;
cur->dict = xmlDictCreate(); cur->dict = xmlDictCreate();
#ifdef WITH_XSLT_DEBUG #ifdef WITH_XSLT_DEBUG
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
@ -1901,8 +1902,6 @@ xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) {
xmlFree(prop); xmlFree(prop);
} }
xsltParseStylesheetExtPrefix(style, top);
cur = top->children; cur = top->children;
/* /*
@ -2048,9 +2047,6 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
return(NULL); return(NULL);
} }
xsltParseStylesheetExcludePrefix(ret, cur); xsltParseStylesheetExcludePrefix(ret, cur);
if (!ret->nopreproc)
xsltPrecomputeStylesheet(ret, cur);
if ((IS_XSLT_ELEM(cur)) && if ((IS_XSLT_ELEM(cur)) &&
((IS_XSLT_NAME(cur, "stylesheet")) || ((IS_XSLT_NAME(cur, "stylesheet")) ||
(IS_XSLT_NAME(cur, "transform")))) { (IS_XSLT_NAME(cur, "transform")))) {
@ -2058,6 +2054,16 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
xsltGenericDebug(xsltGenericDebugContext, xsltGenericDebug(xsltGenericDebugContext,
"xsltParseStylesheetProcess : found stylesheet\n"); "xsltParseStylesheetProcess : found stylesheet\n");
#endif #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); xsltParseStylesheetTop(ret, cur);
} else { } else {
@ -2105,6 +2111,7 @@ xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) {
template->elem = (xmlNodePtr) doc; template->elem = (xmlNodePtr) doc;
template->content = doc->children; template->content = doc->children;
xsltAddTemplate(ret, template, NULL, NULL); xsltAddTemplate(ret, template, NULL, NULL);
ret->literal_result = 1;
} }
return(ret); return(ret);

View File

@ -447,6 +447,10 @@ struct _xsltStylesheet {
* all document text strings were internalized * all document text strings were internalized
*/ */
int internalized; int internalized;
/*
* Literal Result Element as Stylesheet c.f. section 2.3
*/
int literal_result;
}; };
/* /*

View File

@ -44,7 +44,7 @@ extern "C" {
* *
* extra version information, used to show a CVS compilation * extra version information, used to show a CVS compilation
*/ */
#define LIBXSLT_VERSION_EXTRA "-CVS998" #define LIBXSLT_VERSION_EXTRA "-CVS999"
/** /**
* WITH_XSLT_DEBUG: * WITH_XSLT_DEBUG:

View File

@ -44,9 +44,12 @@ la valeur nulle -->
</xsl:call-template> </xsl:call-template>
</xsl:when> </xsl:when>
<xsl:when test="$action='repl'"> <xsl:when test="$action='repl'">
<xsl:choose>
<xsl:when test="$action='del'"> <xsl:when test="$action='del'">
<xsl:call-template name="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:with-param name="type">toto</xsl:with-param>
</xsl:call-template> </xsl:call-template>
</xsl:when> </xsl:choose> </xsl:when> </xsl:choose>