XSLT if属性是否存在/ else

car*_*rlo 6 xml xslt xpath

我对XSLT很新,因此我想知道检查属性是否存在的最佳实践.我的XML看起来像这样:

<root>
    <languages>
        <lang id="EN">English<lang>
        <lang id="FR">French<lang>
        <lang id="DE">German</lang>
    </languages>
    <items>
        <item lang="EN">test 1</item>
        <item>test 2</item>
        <item lang="FR">item 3</item>
    </items>
</root>
Run Code Online (Sandbox Code Playgroud)

请注意,'item'元素的'lang'属性是可选的.

现在我想使用-loop循环遍历项目,同时检查它是否具有"lang"属性.如果是,我想使用ID获取整个字符串(例如EN - >'English').如果未设置该属性,我希望它写"无语言集"或类似的东西.

现在我使用下面的代码但是我在质疑自己是否无法以更有效的方式完成.

<xsl:for-each select="//root/items/item">
    <xsl:variable name="cur_lang" select="@lang" /> <!-- first I store the attr lang in a variable -->
    <xsl:choose>
        <xsl:when test="@lang"> <!-- then i test if the attr exists -->
            <xsl:value-of select="//root/languages/lang[@id=$cur_lang]" /> <!-- if so, parse the element value -->
        </xsl:when>
        <xsl:otherwise>
            No language set <!-- else -->
        </xsl:otherwise>
    </xsl:choose>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)

有什么建议/提示吗?

Ian*_*rts 7

使用密钥可能更有效.您可以使用模板外部的顶级元素定义键

<xsl:key name="langByCode" match="lang" use="@id" />
Run Code Online (Sandbox Code Playgroud)

然后在循环中你可以简单地说

<xsl:when test="@lang"> <!-- then i test if the attr exists -->
   <xsl:value-of select="key('langByCode', @lang)" />
</xsl:when>
Run Code Online (Sandbox Code Playgroud)

但一般来说,对整个事情采用更自然的XSLT方法是使用模板匹配而不是for-eachif:

<xsl:template match="item[@lang]">
  <xsl:value-of select="key('langByCode', @lang)" />
</xsl:template>

<xsl:template match="item">
  <xsl:text>No language set</xsl:text>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

使用这些模板,您可以执行此操作<xsl:apply-templates select="/root/items/item" />,它将自动为每个项目选择适当的模板.规则是它将使用最具体的模板,因此item[@lang]那些具有lang属性的项目和item那些不具有属性的项目.

第三种可能性是我在SO上学到的一个小技巧,将整个if/else检查放入单个XPath表达式中

<xsl:value-of select="
  substring(
    concat('No language set', key('langByCode', @lang)),
    1 + (15 * boolean(@lang))
  )" />
Run Code Online (Sandbox Code Playgroud)

这里的技巧是boolean(@lang)当被视为数字时,1如果lang属性存在,0如果不存在.如果有一个lang="EN",比如说,那么我们构造一个字符串"No language setEnglish",然后从第16个字符开始获取子字符串,即"English".如果没有 lang属性,我们构造字符串"No language set"(因为空节点集的字符串值是空字符串)并从第一个字符(即整个字符串)开始获取子字符串.

你可以使用与其他属性相同的技巧,例如假设我们有一个可选的颜色属性并且想要说它"No color specified"是否缺席,你可以用

<xsl:value-of select="substring(
   concat('No color specified', @color),
   1 + (18 * boolean(@color))
 )" />
Run Code Online (Sandbox Code Playgroud)