Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT if属性存在/else_Xml_Xslt_Xpath - Fatal编程技术网

Xml XSLT if属性存在/else

Xml XSLT if属性存在/else,xml,xslt,xpath,Xml,Xslt,Xpath,我对XSLT非常陌生,因此我想知道检查属性存在性的最佳实践是什么。我的XML如下所示: <root> <languages> <lang id="EN">English<lang> <lang id="FR">French<lang> <lang id="DE">German</lang> </languages> &

我对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>

英语
法语
德国的
测试1
测试2
项目3
请注意,“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>

没有语言集

有什么建议/提示吗?

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

<xsl:key name="langByCode" match="lang" use="@id" />
有了这些模板,您就可以执行
,它会自动为每个项目选择合适的模板。规则是,它将使用最具体的模板,因此
项[@lang]
一个用于具有
lang
属性的项,而普通
一个用于不具有该属性的项

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

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

如果您能够使用XSLT 3.0,另一种选择是(另一个有用的链接:)

XML输入(固定格式)


英语
法语
德国的
测试1
测试2
项目3
XSLT 3.0

<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" extension-element-prefixes="xs map">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="lang-map" as="map(xs:string, xs:string)" 
        select="map:new(
        for $lang in /*/languages/lang 
        return 
            map{$lang/@id := $lang/string()}
        )"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="languages"/>

    <xsl:template match="item[@lang and map:contains($lang-map,@lang)]">
        <item><xsl:value-of select="$lang-map(current()/@lang)"/></item>
    </xsl:template>

    <xsl:template match="item">
        <item>No language found.</item>
    </xsl:template>

</xsl:stylesheet>

找不到语言。
输出

<root>
   <items>
      <item>English</item>
      <item>No language found.</item>
      <item>French</item>
   </items>
</root>

英语
找不到语言。
法语

您可以添加一个示例,说明在您提供的输入中应该提供什么样的确切输出吗?Carlo,您忘记提供所需的输出了--我想您希望扩展语言字符串替换当前的
lang
属性值。当转换应用于提供的XML文档时,请编辑问题并提供想要的结果。谢谢,我尝试使用,但当我这样做时,页面不会加载。我可能做错了什么?通过从现在开始移动解决了问题。如果有一个额外的可选属性,比如“color”,我该怎么办?@carlo我在另一个技巧上添加了一些注释(从Dimitre Novatchev这里开始),将if/else压缩到一个XPath表达式中,这意味着对于lang/no lang情况,不需要显式的if或单独的模板。
<xsl:value-of select="substring(
   concat('No color specified', @color),
   1 + (18 * boolean(@color))
 )" />
<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>
<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" extension-element-prefixes="xs map">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="lang-map" as="map(xs:string, xs:string)" 
        select="map:new(
        for $lang in /*/languages/lang 
        return 
            map{$lang/@id := $lang/string()}
        )"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="languages"/>

    <xsl:template match="item[@lang and map:contains($lang-map,@lang)]">
        <item><xsl:value-of select="$lang-map(current()/@lang)"/></item>
    </xsl:template>

    <xsl:template match="item">
        <item>No language found.</item>
    </xsl:template>

</xsl:stylesheet>
<root>
   <items>
      <item>English</item>
      <item>No language found.</item>
      <item>French</item>
   </items>
</root>