2024年玩xml真是笑死了(xsl)

昨天大早上的6点就醒了,翻来覆去睡不着,就开始胡思乱想。忘记是什么缘起了,反正突然想到一个问题,博客这种静态站,又要输出html,又要输出rss。太冗余了。要不直接把内容存在RSS里。然后用js去fetch()。。。。

等等,死去的记忆突然攻击我。RSS不就是XML,XML似乎有个加皮肤的技术。于是就更睡不着了,起床一查,原来是 XSLT 转换成 HTML 然后就可以自由发挥了。

可行性没问题,准备找个前人的例子开抄。比如 2021年Nathan Clark的Styling an RSS Feed With XSLT2023年Darek Kay的Style your RSS feed

思路就很匹配,执行效果也不错。我想百尺竿头更进一步,把 XSL 给 inline 到 RSS 里,避免额外的加载,节省一次网络请求。吗,没想到这下麻烦大了,折腾到现在才有个初步结果。直接贴源码:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="#stylesheet"?>

<some_xml_root xmlns:shit="http://xxx">

<xsl:stylesheet xml:id="stylesheet" version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat" version="5.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
  <html>
    ...
  </html>

</xsl:template>
</xsl:stylesheet>

</some_xml_root>

这里的 href="#stylesheet" 方法,是官方推荐的 。但是要起效果,一定注意 type="text/xsl" 别抄成网上的 application/xslt+xml

主要浪费时间的坑点主要在根的 xmlns 上。这玩意把 xpath 给搞挂了。比如 sitemap你写

<xsl:for-each select="/urlset/url">

好好的,加上 xmlns 就得写成:

<xsl:for-each select="/*[local-name() = 'urlset']/*[local-name() = 'url']">

怪不得现在没人玩XML了。这破玩意没法直观的本地调试,还得靠各种第三方 validator,反人类啊。

于是把根的 xmlns 直接改成 tag namespace。也就是 xmlns:shit 。反正你namespace冲突了关我什么事?而且说实话,xmlns这玩意除了坑各种解析器不好写之外,并没有什么卵用。我以前写都是想办法去掉 xmlns 再解析。感觉这一块真的 over-engineering 了。 好像有点明白 namespace 是干嘛的了。这玩意主要解决一个sb需求:允许多个XML合并到一个文件里。这不就得考虑如何分清楚tag谁是谁的。。。。并且标准已经挖好坑了,一个XML有且只有一个root。。你把别的 tag 合并进来,那的确不容易区分。还有这样写不会造成文件体积膨胀吗?真是xsl笑死了。

接下来的问题就是如何生成一个规规矩矩的 html5 doctype。搜了下 doctype-system就可以了。本来其实可以在<xsl:template>后面加上

<xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html&gt;</xsl:text>

但实际只加这个是不行的。

另外吐槽下 Chrome,默认的viewer把xml渲染成html了,在 devtool 里通过 $x() 无法直接调试xpath,还得靠别的第三方工具。(⊙﹏⊙)

这可能就是XSL的核心问题了——没法方便直观的调试,挂了就给你白屏。有点react那种白屏的 ptsd 感觉了。

Comments