【问题标题】:Tricky XSLT transformation棘手的 XSLT 转换
【发布时间】:2011-10-17 02:15:22
【问题描述】:

假设一个标签和项目对的 XML 树,每个都包含需要转换的标记:

<list>
   <label>ABC<ptr target="#note-1"/></label>
   <item><ref type="link">123</ref></item>
   <label>DEF<ptr target="#note-2"/></label>
   <item><ref type="link">456</ref></item>
   ...
</list>

(注意,&lt;label&gt;&lt;item&gt; 元素内的标记只是一个示例。这些元素中可能包含任意数量的标记。因此,将处理嵌套标记通过模板规则。使用 XSL 字符串函数等来处理这种嵌套标记并不是一个理想的解决方案,因为可能的标记数量很大。)

假设目标是将其转换为 HTML 无序列表,如下所示:

<ul>
   <li>ABC<sup>1</sup> <a href="link1.html">123</a></li>
   <li>DEF<sup>2</sup> <a href="link2.html">456</a></li>
   ...
</ul>

我一直在尝试将 &lt;label&gt;&lt;item&gt; 节点对与前面的::sibling 轴匹配,例如

   <xsl:template match="list[@type='index']/item[preceding-sibling::label]" >
    <li><xsl:value-of select="./preceding-sibling::label[1]"/> <xsl:apply-templates/></li>
   </xsl:template>

但我的输出两次发出&lt;label> 的内容:一次在&lt;li&gt; 元素之前(正确转换),另一次在&lt;li&gt; 元素内部(没有转换),如下所示:

  <ul>
     ABC<sup>1</sup>
     <li>ABC <a href="link1.html">123</a></li>
     DEF<sup>2</sup>
     <li>DEF <a href="link2.html">456</a></li>
     ...
  </ul>

我了解&lt;li&gt; 中的&lt;label&gt; 内容没有被转换,因为我使用的是&lt;xsl:value-of&gt;。我只是想说明我想要实现的目标,即在&lt;li&gt; 中获取&lt;label&gt; &lt;item&gt; 的内容。

如果我添加以下模板来抑制来自 &lt;label&gt; 元素的第二个内容实例:

<xsl:template match="list[@type='index']/label"></xsl:template>

然后删除来自&lt;label&gt; 的冗余内容集,但不是正确的内容。例如,

<ul>
     <li>ABC <a href="link1.html">123</a></li>
     <li>DEF <a href="link2.html">456</a></li>
     ...
  </ul>

所以,我的问题是,如何将 &lt;label&gt;&lt;item&gt; 中的内容放入单个 &lt;li&gt; 元素中,同时让样式表中的其他模板处理该内容?

【问题讨论】:

    标签: xslt


    【解决方案1】:

    这在 XSLT 中非常简单

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="list">
      <ul>
        <xsl:apply-templates select="label"/>
      </ul>
     </xsl:template>
     <xsl:template match="label">
      <li>
       <xsl:value-of select="."/>
    
       <xsl:variable name="vPos" select=
           "substring-after(ptr/@target, '#note-')"/>
       <sup>
         <xsl:value-of select="$vPos"/>
       </sup>
       <xsl:apply-templates select=
          "following-sibling::*[1][self::item]">
        <xsl:with-param name="pPos" select="$vPos"/>
       </xsl:apply-templates>
      </li>
     </xsl:template>
    
     <xsl:template match="item">
      <xsl:param name="pPos"/>
       <a href="{@type}{$pPos}.html">
         <xsl:value-of select="."/>
       </a>
     </xsl:template>
    </xsl:stylesheet>
    

    在提供的 XML 文档上应用此转换时(更正为格式正确):

    <list>
       <label>ABC<ptr target="#note-1"/></label>
       <item><ref type="link">123</ref></item>
       <label>DEF<ptr target="#note-2"/></label>
       <item><ref type="link">456</ref></item>
    </list>
    

    产生想要的正确结果

    <ul>
       <li>ABC<sup>1</sup>
          <a href="1.html">123</a>
       </li>
       <li>DEF<sup>2</sup>
          <a href="2.html">456</a>
       </li>
    </ul>
    

    【讨论】:

    • Dimitre:感谢您的回复。我没有明确指出,除了源 XML 中的 &lt;ptr&gt;&lt;ref&gt; 元素之外,还可能出现另外 20 个左右不同的标签。您提供的解决方案仅处理我在示例中使用的两个标签。我的目标是有一个更通用的解决方案,我可以在&lt;label&gt;&lt;item&gt; 的内容上匹配任意数量的模板。但是,如有必要,我可以使用您的解决方案并使用 XSLT 函数处理这些附加元素。但我更喜欢依赖模板,因为它看起来更干净。
    • @sarcanon:请编辑问题以使其更相关或更好,接受此答案并提出新问题,通过评论告诉我。
    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多