Good coding style to do case-select in XSLT
I want to have a page display A,B,C,D depending on the return value from XML value (1,2,3,4). My approaches are by javascript or XSLT:choose. I want to know which way is better, and why? Can I do this case-select in .cs code (good or bad)? Should I javascript code in XSLT? Can the community please advise? Thanks.
Below are the code.
Javascript way (this one works):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:js="urn:custom-javascript">
<xsl:template match="page">
<msxsl:script language="JavaScript" implements-prefix="js">
<![CDATA[
function translateSkillLevel(level)
{
switch (level)
{
case 0: return "Level 1";
case 1: return "Level 2";
case 2: return "Level 3";
}
return "unknown";
}
]]>
</msxsl:script>
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<xsl:for-each select="/page/Skill">
<tr>
<td>
<!-- difference here -->
<script type="text/javascript">
document.write(translateSkillLevel(<xsl:value-of select=开发者_如何学JAVA"@level"/>));
</script>
</td>
</tr>
</xsl:for-each>
</table>
</div>
</xsl:template>
</xsl:stylesheet>
Javascript way (this one doesn't work, getting undefined js tag):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:js="urn:custom-javascript">
<xsl:template match="page">
<msxsl:script language="JavaScript" implements-prefix="js">
<![CDATA[
function translateSkillLevel(level)
{
switch (level)
{
case 0: return "Level 1";
case 1: return "Level 2";
case 2: return "Level 3";
}
return "unknown";
}
]]>
</msxsl:script>
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<xsl:for-each select="/page/Skill">
<tr>
<td>
<!-- difference here -->
<xsl:value-of select="js:translateSkillLevel(string(@level))"/>
</td>
</tr>
</xsl:for-each>
</table>
</div>
</xsl:template>
</xsl:stylesheet>
XSLT way:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<xsl:for-each select="/page/Skill">
<tr>
<td>
<xsl:choose>
<xsl:when test="@level = 0">
Level 1
</xsl:when>
<xsl:when test="@level = 1">
Level 2
</xsl:when>
<xsl:when test="@level = 2">
Level 3
</xsl:when>
<xsl:otherwise>
unknown
</xsl:otherwisexsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:for-each>
</table>
</div>
</xsl:template>
</xsl:stylesheet>
EDIT:
Also, I have some inline javascript functions for form submit.
<input type="submit" onclick="javascript:document.forms[0].submit();return false;"/>
Out of these two, I would definitely go for the XSLT way. There's no need to invoke an entire script engine for just this.
First, the XSLT way would be something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<xsl:apply-templates/>
</table>
</div>
</xsl:template>
<xsl:template match="Skill">
<tr>
<td>
<xsl:apply-templates select="@level"/>
</td>
</tr>
</xsl:template>
<xsl:template match="@level">Unknown</xsl:template>
<xsl:template match="@level[3>.]">
<xsl:value-of select="concat('Level ',.+1)"/>
</xsl:template>
</xsl:stylesheet>
Input:
<page>
<Skill level="1"/>
<Skill level="4"/>
</page>
Output:
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<tr>
<td>Level 2</td>
</tr>
<tr>
<td>Unknown</td>
</tr>
</table>
</div>
Second: You first stylesheet doesn't "work" as it is, unless you define into some HTML SCRIPT
element the translateSkillLevel
javascript function (or better, an external LINK
).
Third: Your second stylesheet could "work", but inline extension functions implementations are not the standard XSLT extension mechanism. That's why you are using a not standard extension element making your stylesheet not portable between XSLT processors.
No extension functions are necessary, XSLT is powerful and flexible enough.
The XSLT implementation I would recommend is this (largely customizable, flexible and extensible):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my">
<my:skills>
<s v="0" d="1"/>
<s v="1" d="2"/>
<s v="2" d="3"/>
<other>unknown</other>
</my:skills>
<xsl:variable name="vSkills" select=
"document('')/*/my:skills/*"/>
<xsl:variable name="vUnknown" select=
"document('')/*/my:skills/other"/>
<xsl:template match="page">
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<xsl:apply-templates select="Skill/@level"/>
</table>
</div>
</xsl:template>
<xsl:template match="@level">
<tr>
<td>
<xsl:variable name="vSkill" select=
"$vSkills[@v=current()]/@d"/>
<xsl:value-of select="$vSkill|$vUnknown[not($vSkill)]"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
when the above transformation is applied to the following XML document:
<page>
<Skill level="1"/>
<Skill level="4"/>
</page>
the wanted, correct result is produced:
<div id="skill">
<table border="0" cellpadding="1" cellspacing="1">
<tr>
<th>Level</th>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>unknown</td>
</tr>
</table>
</div>
Do note:
All the rules for translating a current skill value to a display value are specified as data.
The decision data can be in a separate document so that complete parameterization is achieved.
We do not rely on an accidental dependency ( such as dispValue = value +1) -- any relation b/n the current value and the display value can be expressed.
There is absolutely no conditional logic in the XSLT code!
精彩评论