如何根据xslt代码中的条件限制标记的属性添加

时间:2012-07-03 12:30:31

标签: xslt xslt-1.0

我们如何根据xslt中的某些条件创建属性。

我的输入xml有一个标记:

          <track external="http://mysite.com"  />
              or
           <track  local="/myfolder" />

并在这个'track元素中出现外部或本地属性但不是这些中的任何一个,我必须将其转换为

       <a xhtml:href="@external value" xmlns="http://www.w3.org/1999/xhtml" /> 

如果'track'元素出现'extrenal'属性或进入

       <a xlink:href="@local value" xmlns="http://www.w3.org/1999/xlink" /> 

如果'track'元素出现'local'属性

XSLT尝试过:

     <a xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">      

      <xsl:for-each select="child::*" >
        <xsl:choose>

          <xsl:when test="name()='track'">
             <xsl:if test="@local">
            <xsl:attribute name="xlink:href">

            <xsl:value-of select="@local" />
            </xsl:attribute>
            </xsl:if>
               <xsl:if test="@external">
            <xsl:attribute name="xhtml:href">

            <xsl:value-of select="@external" />
            </xsl:attribute>
            </xsl:if>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each>

      </a>

但抛出异常,因为我根据条件创建了'a'元素的属性。这在XSLT 1.0中是不被接受的,是否有任何方法可以根据XSLT 1.0中的某些条件为我的'a'元素显示属性。

3 个答案:

答案 0 :(得分:3)

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xhtml="http://www.w3.org/1999/xhtml"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:mappings>
  <map from="external" to="xhtml"/>
  <map from="local" to="xlink"/>
 </my:mappings>

 <xsl:variable name="vMaps" select="document('')/*/my:mappings/*"/>
 <xsl:variable name="vNamespaces" select="document('')/*/namespace::*"/>

 <xsl:template match="/*">
   <t><xsl:apply-templates/></t>
 </xsl:template>

 <xsl:template match="track">
     <xsl:element name="a"
       namespace="{$vNamespaces[name()=$vMaps[@from=name(current()/@*)]/@to]}">
       <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{$vMaps[@from=name(current())]/@to}:href"
    namespace="{$vNamespaces[name()=$vMaps[@from=name(current())]/@to]}">
    <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档时

<t>
    <track external="http://mysite.com"  />
    <track  local="/myfolder" />
</t>

会产生想要的正确结果:

<t xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
   <a xmlns="http://www.w3.org/1999/xhtml" xhtml:href="http://mysite.com"/>
   <a xmlns="http://www.w3.org/1999/xlink" xlink:href="/myfolder"/>
</t>

请注意此解决方案具有一些独特的功能,例如:

  1. 没有使用条件指令,因此代码更简单,更不容易出错。

  2. 使用纯粹的“推”式。

  3. 产生了确切的想要结果。

答案 1 :(得分:1)

没有什么能阻止您在XSLT 1.0中有条件地添加属性。顺便说一句,避免在XSLT中使用for-each而是使用模板。这是track节点的专用模板。

<xsl:template match='track'>

    <a xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
        <xsl:if test="@local">
            <xsl:attribute name="xlink:href">
                    <xsl:value-of select="@local" />
            </xsl:attribute>
        </xsl:if>
        <xsl:if test="@external">
            <xsl:attribute name="xhtml:href">
                <xsl:value-of select="@external" />
            </xsl:attribute>
        </xsl:if>
    </a>

</xsl:template>

正如Tim C所提到的,更好的模式是通过不同的模板处理不同类型的传入属性。尽管如此,这个更干净,因为你不会陷入条件障碍。

<xsl:template match='track'>
    <a><xsl:apply-templates select='@*' /></a>
</xsl:template>

<xsl:template match='@local' xmlns:xlink="http://www.w3.org/1999/xlink">
    <xsl:attribute name="xlink:href">
            <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

<xsl:template match='@external' xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <xsl:attribute name="xhtml:href">
        <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

您可以在this XMLPlayground中看到这两种方法。

答案 2 :(得分:1)

您应该使用模板匹配来匹配相关情况。首先,不要使用 xsl:for-each ,而是使用 xsl:apply-templates

<xsl:apply-templates select="*" />

然后有单独的模板来匹配是否存在本地外部属性

<xsl:template match="track[@external]">
    <a xhtml:href="{@external}" />
</xsl:template>

<xsl:template match="track[@local]">
    <a xlink:href="{@local}" />
</xsl:template>

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="album">
        <p>
        <xsl:apply-templates select="*" />
        </p>
    </xsl:template>

    <xsl:template match="track[@external]">
        <a xhtml:href="{@external}" />
    </xsl:template>

    <xsl:template match="track[@local]">
        <a xlink:href="{@local}" />
    </xsl:template>
</xsl:stylesheet>

应用于以下XSLT

<album>
   <track external="http://mysite.com"/>
   <track local="/myfolder"/>
</album>

以下是输出

<p xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/">
   <a xhtml:href="http://mysite.com" />
   <a xlink:href="/myfolder" />
</p>