Subject: Re: [xsl] Parameter substitution From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx> Date: Wed, 19 Dec 2001 18:10:10 +0000 |
Hi Curtis, > Below is given a fragment from an XML document. Of note are the > contents of the <ErrorText> nodes; the first one has a value of "%1 > %2 is not a valid date format.". > > My task, (you guessed it) is to replace each %1, %2 etc.. with a > string built from the correspondong ErrorParameter (formatted nicely > of course) . Being relatively new to XSLT, I can't think of a way to > accomplish this in a generic manner. Has anyone got any ideas? I > can't think of an approach that will actually work! It's a little tedious because XPath string-handling isn't the best (roll on regexps), but it's certainly possible. To work through the string, you need a recursive template; it needs to take the string in which you're replacing parameter references, and a list of parameters that you want to replace the references with: <xsl:template name="substituteParameters"> <xsl:param name="string" /> <xsl:param name="parameters" select="/.." /> ... </xsl:template> You need to work through the string a bit at a time. If the string doesn't contain any % characters, then you know that you can just output the string with no changes, so that's the basic test on which the template hinges: <xsl:template name="substituteParameters"> <xsl:param name="string" /> <xsl:param name="parameters" select="/.." /> <xsl:choose> <xsl:when test="contains($string, '%')"> ... </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </xsl:template> Now, given that you have a string with a % in it, you want to output: - the string up to the % - the parameter in the position indicated by the number after the % - the result of calling this same template on the rest of the string (after the number) The first bit's easy - you can use the substring-before() function to get the bit before the %: <xsl:template name="substituteParameters"> <xsl:param name="string" /> <xsl:param name="parameters" select="/.." /> <xsl:choose> <xsl:when test="contains($string, '%')"> <xsl:value-of select="substring-before($string, '%')" /> ... </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </xsl:template> The second bit's a little more complicated - you need to get the number after the %. If you can guarantee that there aren't going to be more than 9 parameters, then you only need to get the first character after the %, so I'll assume that's the case (let me know if it's not). So you can use the following to get the first character after the %: substring(substring-after($string, '%'), 1, 1) That gives you (a string representation of) a number, which you can use to index into the parameters passed as the value of the $parameters parameter: $parameters[position() = substring(substring-after($string, '%'), 1, 1)] or: $parameters[number(substring(substring-after($string, '%'), 1, 1))] I'd apply templates to this parameter - you can have a template matching ErrorParameter elements that does the relevant pretty formatting: <xsl:template name="substituteParameters"> <xsl:param name="string" /> <xsl:param name="parameters" select="/.." /> <xsl:choose> <xsl:when test="contains($string, '%')"> <xsl:value-of select="substring-before($string, '%')" /> <xsl:apply-templates select="$parameters[number(substring( substring-after($string, '%'), 1, 1))]" /> ... </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </xsl:template> Finally, the recursive call to the template needs to pass in the same set of parameters whilst amending the string to being the 'rest' of the substring after the '%': <xsl:template name="substituteParameters"> <xsl:param name="string" /> <xsl:param name="parameters" select="/.." /> <xsl:choose> <xsl:when test="contains($string, '%')"> <xsl:value-of select="substring-before($string, '%')" /> <xsl:apply-templates select="$parameters[number(substring( substring-after($string, '%'), 1, 1))]" /> <xsl:call-template name="substituteParameters"> <xsl:with-param name="string" select="substring(substring-after($string, '%'), 2)" /> <xsl:with-param name="parameters" select="$parameters" /> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="." /> </xsl:otherwise> </xsl:choose> </xsl:template> To call it, you'd do something like the following (assuming that SynchError is the current node): <xsl:call-template name="substituteParameters"> <xsl:with-param name="string" select="ErrorText" /> <xsl:with-param name="parameters" select="ErrorParameter" /> </xsl:call-template> Having said all of that, you would be a lot better off if you could change the XML structure so that you used elements to indicate where the parameters should be inserted. Something like: <ErrorText> <Insert param="1" /> <Insert param="2" /> is not a valid date format. </ErrorText> That way, you could just apply templates to the content of the ErrorText element and use templates matching Insert elements to insert the value of the relevant parameter. I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Parameter substitution, Curtis Burisch | Thread | Re: [xsl] Parameter substitution, Trevor Nash |
RE: [xsl] Retrieving an Attribute f, Michael Kay | Date | Re: [xsl] Parameter substitution, Trevor Nash |
Month |