xml - XSLT 1.0 支持中间结果吗?

标签 xml xslt xpath foreach return

TL;DR:我如何表示 <apply-templates />带有 XPath 的语句?

<小时/>

我有一个整理信息的模板。我想以不止一种不同的方式进一步处理这些信息,所以我想知道是否有一种方法可以从 XSLT 中的模板进行“返回”。

示例:我有一个 XHTML 片段:

<page html:xmlns="html namespace">
  <html:p>
    The <html:a href="/foo">Tropical Foo</html:a> uses <html:a href="bar-language">Bar</html:a> to implement <html:a href="/programs/fizzbuzz>FizzBuzz</html:a>
  </html:p>
</page>

我有一个要提取的模板 <a>带有 href 的标签来自 HTML 片段。我想重复使用它两次来预取页面并添加“链接”栏,如下所示:

<html>
  <head>
    <link rel="prefetch" href="/foo" />
    <link rel="prefetch" href="bar-language" />
    <link rel="prefetch" href="/programs/fizzbuzz" />
  </head>
  <body>
    <main>
      <p>
        The <a href="/foo">Tropical Foo</a> uses <a href="bar-language">Bar</a> to implement <a href="/programs/fizzbuzz>FizzBuzz</a>
      </p>
    </main>
    <aside>
      <h2>Linked</h2>
      <ul>
        <li><a href="/foo">Tropical Foo</a></li>
        <li><a href="bar-language">Bar</a></li>
        <li><a href="/programs/fizzbuzz>FizzBuzz</a></li>
      </ul>
    </aside>
  </body>
</html>

这在 XSLT 1.0 中可能吗?

<小时/>

如果更容易的话,我有一个相关的问题变体,我使用样式表转换整个文档,然后想要使用转换后的版本。我知道我可以<xsl:include>其他文档转换样式表并写入 <xsl:apply-templates select="document('other.xml')"/> ,但我想进一步改造这个结果。

最佳答案

XSLT 1.0 在 XPath 1.0 数据模型合并的四种数据类型(字符串、数字、 bool 值、节点集)中添加了一种数据类型:结果树片段 ( https://www.w3.org/TR/xslt-10/#section-Result-Tree-Fragments ):

This additional data type is called result tree fragment. A variable may be bound to a result tree fragment instead of one of the four basic XPath data-types (string, number, boolean, node-set). A result tree fragment represents a fragment of the result tree. A result tree fragment is treated equivalently to a node-set that contains just a single root node. However, the operations permitted on a result tree fragment are a subset of those permitted on a node-set. An operation is permitted on a result tree fragment only if that operation would be permitted on a string (the operation on the string may involve first converting the string to a number or boolean). In particular, it is not permitted to use the /, //, and [] operators on result tree fragments.

因此,您可以将中间结果作为结果树片段,但如果您希望使用超过 xsl:copy-of 的任何结果或xsl:value-of或者获取超出 XSLT 1.0 范围所需的字符串值,并且在大多数 XSLT 1.0 处理器中,您都支持类似 exsl:node-set 的扩展函数为此,它将结果树片段转换为节点集。

这是一个简单的示例,它首先处理输入中的一些元素以添加属性,然后使用 exsl:node-set 将结果树片段转换为节点集。 ( http://exslt.org/exsl/functions/node-set/index.html ) 然后为两种不同的模式使用该节点集两次:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    xmlns:msxml="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="exsl msxml"
    version="1.0">

  <xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>

  <xsl:variable name="numbered-items-rtf">
      <xsl:apply-templates select="//item" mode="number"/>
  </xsl:variable>

  <xsl:variable name="numbered-items" select="exsl:node-set($numbered-items-rtf)/item"/>

  <xsl:template match="item" mode="number">
      <xsl:copy>
          <xsl:attribute name="index">
              <xsl:number/>
          </xsl:attribute>
          <xsl:copy-of select="node()"/>
      </xsl:copy>
  </xsl:template>

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

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
        <style>
            nav ul li { display: inline }
            nav ul { list-item-type: none }
        </style>
      </head>
      <body>
          <h1>Example</h1>
          <nav>
              <ul>
                  <xsl:apply-templates select="$numbered-items" mode="nav"/>
              </ul>
          </nav>
          <section>
              <h2>List</h2>
              <ul>
                  <xsl:apply-templates select="$numbered-items"/>
              </ul>
          </section>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="item">
      <li id="item-{@index}">
          <xsl:apply-templates/>
      </li>
  </xsl:template>

  <xsl:template match="item" mode="nav">
      <li>
          <a href="#item-{@index}">
              <xsl:apply-templates/>
          </a>
      </li>
  </xsl:template>

</xsl:stylesheet>

示例输入,例如

<root>
    <items>
        <item>foo</item>
        <item>bar</item>
        <item>baz</item>
    </items>
</root>

转换为

<!DOCTYPE html SYSTEM "about:legacy-doctype">
<html>
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=utf-16">
    <title>.NET XSLT Fiddle Example</title>
    <style>
            nav ul li { display: inline }
            nav ul { list-item-type: none }
        </style>
  </head>
  <body>
    <h1>Example</h1><nav><ul>
        <li><a href="#item-1">foo</a></li>
        <li><a href="#item-2">bar</a></li>
        <li><a href="#item-3">baz</a></li>
      </ul></nav><section><h2>List</h2>
      <ul>
        <li id="item-1">foo</li>
        <li id="item-2">bar</li>
        <li id="item-3">baz</li>
      </ul></section></body>
</html>

https://xsltfiddle.liberty-development.net/pPqsHUd/1

缺点是某些 XSLT 1.0 处理器不支持 exsl:node-set功能,但在专有命名空间中类似(例如,Microsoft 基于 COM 的 MSXML (3,4,5,6) 处理器仅支持命名空间 msxml:node-set 中的 xmlns:msxml="urn:schemas-microsoft-com:xslt" ,就像(过时的)基于 .NET 的 XslTransform 一样) 。只要您以单个 XSLT 1.0 处理器为目标,您当然可以调整代码以使用正确的命名空间/扩展函数,但如果您想以不同的处理器为目标,您将很难找到一种紧凑而优雅的方法来使用基于function-available因为你没有if XPath 1.0 中的表达式。

所以https://xsltfiddle.liberty-development.net/pPqsHUd/2与例如一起工作Chrome 和 Mozilla 浏览器(例如 Firefox)均支持 exsl:node-set但在 Microsoft IE 和 Edge 中失败,因为它们使用 MSXML 并且不支持 exsl:node-set ,对于他们你需要 <xsl:variable name="numbered-items" select="msxml:node-set($numbered-items-rtf)/item"/>https://xsltfiddle.liberty-development.net/pPqsHUd/3 中所做的那样.

在 IE 中,您可以使用脚本扩展来支持 exsl:node-set但不幸的是,在 Edge 中这不起作用: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7598626/ .

关于xml - XSLT 1.0 支持中间结果吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52947255/

相关文章:

sql-server - xml 为 <选项类型 ="x">y</选项>

javascript - 缺少 XML 节点

arrays - XSL : Construct an Array from a Delimited String

xslt - 如何使用自定义 XSLT 在浏览器中显示 Atom/RSS 提要?

c# - XDocument 更改所有属性名称

java - 使用 ExpandableListView 时将菜单栏放在屏幕底部

java - 问题 使用 SaxParser 解析 XML 文档 - 2047 个字符限制?

xml - XSLT 中的除法和乘法选择值

iphone - 如何获取html文件的一部分?

xml - 用于根据当前节点的内容选择父节点的XPath?