对于下面的(人为)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中完成?
答案 0 :(得分:1)
您可以在此处使用xsl:import
和xsl: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-imports
或xsl:next-match
指令来调用 覆盖模板规则。仅xsl:apply-imports
指令 考虑导入的样式表模块中的模板规则;的xsl:next-match
指令考虑了以下所有其他模板规则: 较低的导入优先级和/或优先级。两条指令都将调用 节点的内置模板规则(请参见 6.6内置模板 规则),如果找不到其他模板规则。
因此,规范本身为您提供了两条指令之间的关系和区别:您不知道在冲突解决之后剩下的所有模板中,声明模板在声明顺序中最后出现了。还值得注意的是,导入的样式表模块不仅是C预处理器包含机制的一种形式。您可能会认为它是转换之间的遗传机制。