在XSLT 1.0中应用多个模板,例如XSLT 2.0的<next-match>

时间:2019-04-16 15:14:04

标签: xslt xslt-1.0 xslt-2.0

对于下面的(人为)HTML示例:

class App extends React.Component {
  state = {
    pages: []
  };

  componentDidMount() {
    axios.get(`https://jsonplaceholder.typicode.com/posts`).then(res => {
      this.setState({ pages: res.data });
    });
  }

  render() {
    const { pages } = this.state;

    if (pages.length === 0) {
      return null;
    }
    return (
      <BrowserRouter>
        <div>
          <Route
            exact
            path="/"
            render={() => (
              <ul>
                {pages.map(page => (
                  <li>
                    <Link to={`/${page.id}`}>{page.title}</Link>
                  </li>
                ))}
              </ul>
            )}
          />
          <Route
            path="/:page"
            render={({ match }) => {
              const pageParam = Number(match.params.page);
              const page = pages.find(p => p.id === pageParam);

              return <div>{page.title}</div>;
            }}
          />
        </div>
      </BrowserRouter>
    );
  }
}

我正在尝试编写一个XSLT 1.0转换,

  • 将顶级<div> <p>lorem <a href="lorem.html" target="_blank">ipsum</a></p> <a href="foo.html" target="top">foo</a> <p><img src="foo.jpg" class="bar"/></p> <img src="bar.jpg" class="bar"/> </div> 列入白名单
  • <p>
  • 白名单href属性
  • <a>
  • 白名单src属性
  • <img>中包装顶级<a><img>

理想情况下,这样做是允许添加更多元素和属性的一种方式。

预期输出:

<p>...</p>

由于<div> <p>lorem <a href="lorem.html">ipsum</a></p> <p><a href="foo.html">foo</a></p> <p><img src="foo.jpg"/></p> <p><img src="bar.jpg"/></p> </div> ,以下XSLT 2.0可以工作:

提琴:https://xsltfiddle.liberty-development.net/6r5Gh3p

<xsl:next-match>

在XSLT 1.0中没有<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/div"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- whitelist <p> as top-level element --> <xsl:template match="/div/p"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- coerce top-level <img> and <a> as children <p> --> <xsl:template match="/div/img|/div/a"> <p><xsl:next-match/></p> </xsl:template> <!-- whitelist href attribute for <a> --> <xsl:template match="a"> <xsl:copy> <xsl:copy-of select="@href"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- whitelist src attribute for <img> --> <xsl:template match="img"> <xsl:copy> <xsl:copy-of select="@src"/> </xsl:copy> </xsl:template> </xsl:stylesheet> ,并且使用下面的模板仅匹配一次,因此<next-match><a>确实包含在<img>中,但是它们的属性却没有被列入白名单:

提琴:https://xsltfiddle.liberty-development.net/94rmq6r

<p>

输出:

  <xsl:template match="/div/img|/div/a">
    <p>
      <xsl:copy><xsl:apply-templates/></xsl:copy>
    </p>
  </xsl:template>

这如何在XSLT 1.0中完成?

2 个答案:

答案 0 :(得分:1)

您可以在此处使用xsl:importxsl:apply-imports

首先,将“白名单”模板放在单独的XSLT文件中(称为“ Whitelist.xslt”)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <!-- whitelist <p> as top-level element -->
  <xsl:template match="/div/p">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist href attribute for <a> -->
  <xsl:template match="a">
    <xsl:copy>
      <xsl:copy-of select="@href"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- whitelist src attribute for <img> -->
  <xsl:template match="img">
    <xsl:copy>
      <xsl:copy-of select="@src"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

然后,您的主要XSLT可以导入它,并在您使用过xsl:apply-imports的任何地方使用xsl:next-match

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:import href="Whitelist.xslt" />

  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/div">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- coerce top-level <img> and <a> as children <p> -->
  <xsl:template match="/div/img|/div/a">
    <p><xsl:apply-imports/></p>
  </xsl:template>
</xsl:stylesheet>

使用导入的样式表时,内部模板的优先级低于主样式表中的模板,因此,始终会首先匹配主模板。

编辑:顺便说一句...我知道您的示例是人为设计的,但是对于这种特殊情况,您可以在不进行下一个匹配或应用导入的情况下重写它,就像这样...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/div|/div/p">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

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

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

  <xsl:template match="a/@href|img/@src">
    <xsl:copy />
  </xsl:template>

  <xsl:template match="@*" />
</xsl:stylesheet>

答案 1 :(得分:0)

我认为正确的答案是XSLT 1.0中没有XSLT 2.0指令xsl:next-match语义上的等效项。会有什么期望。根据规格:

  

用于替代另一个模板规则的模板规则   (请参见6.4 模板规则的冲突解决方法)可以使用   xsl:apply-importsxsl:next-match指令来调用   覆盖模板规则。仅xsl:apply-imports指令   考虑导入的样式表模块中的模板规则;的   xsl:next-match指令考虑了以下所有其他模板规则:   较低的导入优先级和/或优先级。两条指令都将调用   节点的内置模板规则(请参见 6.6内置模板   规则),如果找不到其他模板规则。

因此,规范本身为您提供了两条指令之间的关系和区别:您不知道在冲突解决之后剩下的所有模板中,声明模板在声明顺序中最后出现了。还值得注意的是,导入的样式表模块不仅是C预处理器包含机制的一种形式。您可能会认为它是转换之间的遗传机制。