开发者

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:

  1. All the rules for translating a current skill value to a display value are specified as data.

  2. The decision data can be in a separate document so that complete parameterization is achieved.

  3. 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.

  4. There is absolutely no conditional logic in the XSLT code!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜