---
layout: post
title: 使用XSLT为博客XML文件编写主题一致的样式
tags: [XSLT, 博客优化, XML, Feed]
---

  虽然XML是机器读的内容……不过加上和主题一致的XSLT样式也算是一种细节吧～<!--more-->    

# 起因
  在[上一篇文章](/2025/06/02/optimize.html#%E5%AF%B9%E4%BA%8E%E8%AE%A2%E9%98%85%E8%BD%AF%E4%BB%B6%E7%9A%84%E5%85%BC%E5%AE%B9%E6%80%A7%E6%94%AF%E6%8C%81)中，我提到在提高订阅源兼容性的时候给博客的订阅文件增加了一个XSLT样式。当时使用的样式是从[About Feeds](https://github.com/genmon/aboutfeeds/)下的一个[Issue](https://github.com/genmon/aboutfeeds/issues/26)中找的，里面有个基于[Pretty Feed](https://github.com/genmon/aboutfeeds/blob/main/tools/pretty-feed-v3.xsl)修改成能同时支持RSS和Atom格式的样式。虽然那个样式倒也说不上难看，但总觉得与我的博客整体风格有些割裂，所以这次打算制作一个和我博客主题完全一致的XSLT样式。   

# 制作订阅文件的XSLT样式
  虽然想搞这么一个样式，但是我用的Jekyll引擎不能在引用的布局外添加额外内容……如果我要自己写，要么把我的默认布局拆成头和尾两部分然后用include引用，要么把默认布局的代码直接复制一份到XSLT样式中。这两个方案我都不太满意，第一种我以后在修改默认布局时需要同时从两个文件检查上下文，很不方便；而第二种方案违反了DRY原则，也会增加以后修改的难度。所以要怎么办呢？   
  后来我想了想，如果不能通过直接引用默认布局在外面增加XSLT的代码，那干脆让默认布局引用一个XSLT布局吧！这样我就能在不复制默认布局也不进行过多修改的情况下在外面套XSLT的代码了。于是我就在最外面写了个符合XSLT格式的XML布局，让默认布局引用它。然后再写一个布局引用默认布局，让最外面的布局根据这个布局的名字来判断是否需要使用XSLT的布局，具体的实现可以看我的[layout目录](https://github.com/Mabbs/mabbs.github.io/tree/master/_layouts)。另外有一些地方需要注意一下，作为XML，内容中不能包含未闭合的标签，所有自闭合标签结尾必须添加斜杠，属性必须有值，以及所有标签和属性大小写要一致……还好我平时修改布局文件以及编写内容的时候基本上都遵循了这些规则，所以没什么太多需要改动的地方。   
  当时修改时，是模仿之前的那个样式进行的，原来那个样式在`html`元素上加了XML命名空间，但是`xsl:output`配置的输出却是按照HTML的方式输出，结果导致内容中用于换行的`br`标签在实际转换中全部变成了两个标签……我猜应该是转换器看到XML命名空间后，先按照XHTML的规则把`br`解析成了一开一闭的一对标签，然后又根据HTML的转换规则把这对标签当作两个单独的标签输出了吧……但奇怪的是，只有`br`标签出现了这个问题，像`hr`等其他自闭合标签则没有……既然如此，只要把XML命名空间删掉就OK了。   
  在改完之后虽然整体看上去和其他页面似乎已经很相似了，但总感觉还有些样式不太对劲……我猜应该是和文档类型声明有关系，我平时写的是HTML5，而XSLT默认转出来是HTML4.0……但是我不太清楚怎么解决这个问题，于是问了问AI，AI说在`xsl:output`中加上`doctype-system="about:legacy-compat"`就行。最终改完试了下确实有效😂，样式上也没有出现奇怪的偏移了。   
  最后把写好的布局应用到[/feed.xslt.xml](/feed.xslt.xml)中就可以了，之所以是这个路径是因为我用的[jekyll-feed](https://github.com/jekyll/jekyll-feed)只支持这个位置，至于我自己搞的RSS格式的订阅只需要在开头用`xml-stylesheet`指令声明一下就行了。   

# 给XSLT样式自己的样式
  在写好给订阅文件用的XSLT样式之后，我发现XSLT样式本身也是个XML文件……既然我给订阅文件做了样式，那么也得给XSLT样式文件本身做个样式才对，但如果我单独写一个给它的样式，那岂不是要给样式的样式再写一个样式😂，所以肯定不能这样做。不过仔细想一下，还有个办法，可以让XSLT样式文件自引用自身的样式，这样就能避免之前担心的套娃问题了。所以接下来我应该在XSLT中写一个检测应用样式的XML文件是不是XSLT样式文件的代码，方法很简单，既然XSLT样式中肯定包含`xsl:stylesheet`这个元素，那么我可以判断如果存在这个元素，就可以确定这就是XSLT样式了，如果有人点开看了我就可以展示一个提示信息告诉访客这是一个样式文件，这样访客就不会看到那句“This XML file does not appear to have any style information associated with it. The document tree is shown below.”了😝。   

# 制作Sitemap的XSLT样式
  既然给XSLT样式也加了样式……那我博客还有其他XML文件需要处理吗？似乎还有个Sitemap，我的Sitemap是[jekyll-sitemap](https://github.com/jekyll/jekyll-sitemap)插件生成的……那它支持加样式吗？虽然文档上没有写，不过看了眼源代码发现可以通过创建[/sitemap.xsl](/sitemap.xsl)文件添加，所以就顺手套用之前的样式搞了一个（虽然应该没有访客去看Sitemap😂，毕竟这是给搜索引擎用的）。可惜这些地址都是插件硬编码的，如果可以自己修改位置我就只写一个XSLT样式文件就可以了……   

# 感想
  折腾了这么多整体展示效果还不错，虽然这些文件也许根本没人看😂（本来就不是给人读的），但也算展现了一下博客的细节之处吧，而且在折腾的时候至少还了解了不少关于XML和XSLT的知识（尽管在现代这些好像没啥用了）。当然重要的也许不是了解这些知识，而是这个过程吧……总的来说还是挺有意思的。   