3

我们如何根据 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”元素显示属性。

4

3 回答 3

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. 产生了确切想要的结果。

于 2012-07-03T13:33:54.660 回答
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>

您可以在此 XMLPlayground中看到这两种方法的实际应用。

于 2012-07-03T12:41:26.923 回答
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>
于 2012-07-03T12:44:14.177 回答