问题
If I use <xsl:param>
without specifying a value, the transformer assumes that the value is an empty string.
In other words, if I forgot to specify a value (e.g. <xsl:param name="N"/>
), the compiler doesn't signal an error. This may cause my program to fail silently, which is a bad thing.
How can I specify that my <xsl:param>
must have an explicit value? For example, this code should give me an error because there is no explicit value specified:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:call-template name="F1"></xsl:call-template>
<html>
<head>
<title></title>
</head>
<body>stuff</body>
</html>
</xsl:template>
<xsl:template name="F1">
<xsl:param name="N"/> <!-- I Should Get An Error Here! -->
</xsl:template>
</xsl:stylesheet>
Am looking for a solution in both XSLT 1.0 and XSLT 2.0.
回答1:
You could actually do this with a bit of meta-XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="xsl:call-template">
<xsl:variable name="template" select="/xsl:stylesheet/xsl:template[@name=current()/@name]"/>
<xsl:variable name="call" select="." />
<xsl:variable name="desc">
<xsl:value-of select="concat('call to named template "',$template/@name,'" in ')"/>
<xsl:choose>
<xsl:when test="ancestor::xsl:template/@name">
<xsl:value-of select="concat('named template "',ancestor::xsl:template/@name,'"')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('template matching "',ancestor::xsl:template/@match,'"')" />
</xsl:otherwise>
</xsl:choose>
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:for-each select="$template/xsl:param[not(@select)]">
<xsl:if test="not($call/xsl:with-param[@name=current()/@name])">
<xsl:value-of select="concat('Missing parameter "',@name,'" in ',$desc)" />
</xsl:if>
</xsl:for-each>
<xsl:for-each select="xsl:with-param">
<xsl:if test="not($template/xsl:with-param[@name=current()/@name])">
<xsl:value-of select="concat('Unrecognised parameter "',@name,'" in ',$desc)" />
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()" />
</xsl:stylesheet>
This stylesheet takes any stylesheet as an input, and checks that all call-template's have the right parameters, outputting a message if there's any errors.
This obviously isn't going to put the error checking in the transformer itself, but it will list ALL errors in one go, and can potentially be extended to check for other issues as well.
EDIT: I've adapted it to handle optional parameters, and added in a means of describing where the error is; it's actually a bit of a redesign, with optional parameters simply counting them was going to be tricky, so I removed that bit. Every error is itemized anyway, so the count wasn't really necessary.
回答2:
In XSLT 2.0, of course, you can say <xsl:param required="yes">
, so the problem goes away.
回答3:
<xsl:param name="foo" select="false" />
<xsl:if test="not($foo)">
<xsl:message terminate="yes">You called me with improper params</xsl:message>
</xsl:if>
回答4:
A simple way is checking the input parameter to be not an empty string (specific case mentioned in your comment):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="test">
<xsl:param name="nodefault"/>
<xsl:choose>
<xsl:when test="boolean($nodefault)">
<xsl:message>do your stuff</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Your stuff can't be done</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="test"/>
</xsl:template>
</xsl:stylesheet>
or much simpler:
<xsl:template name="test">
<xsl:param name="nodefault"/>
<xsl:if test="not($nodefault)">
<xsl:message terminate="yes">Your stuff can't be done</xsl:message>
</xsl:if>
<!-- do your stuff -->
</xsl:template>
回答5:
There's a similar option, where you can use a variable that make a choose for the parameter in the called template, for example:
<xsl:template match="/">
<!-- call 1 -->
<xsl:apply-templates select="//encabezado/usuario" mode="forma1">
<xsl:with-param name="nombre" select="'wwww1'"/>
</xsl:apply-templates>
<!-- call 2 -->
<xsl:apply-templates select="//encabezado/usuario" mode="forma1">
</xsl:apply-templates>
<xsl:template match="node()" mode="forma1">
<xsl:param name="nombre"/>
<xsl:param name="valor"/>
<xsl:variable name="nombreLocal">
<xsl:choose>
<xsl:when test="normalize-space($nombre)">
<xsl:value-of select="$nombre"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="local-name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select ="$nombreLocal"/>
</xsl:template>
来源:https://stackoverflow.com/questions/6531449/how-to-force-errors-on-a-xslparam-without-select-attribute