XSLT 教程

XSLT 教程

XSL(eXtensible Stylesheet Language,可扩展样式表语言)是用于转换 XML 文档的语言,XSLT 是其转换核心,能把 XML 转为 HTML、文本或其他 XML 格式。

本教程包含

  • 基础篇:XSL 语言、XSLT 简介、浏览器支持、转换原理
  • 元素篇:template、value-of、for-each、sort、if、choose、apply-templates、import
  • 应用篇:样式、客户端/服务端应用、XPath 配合

为什么学习 XSLT

  • XML 数据展示与格式转换的标准方案
  • 理解数据与展示分离的设计思想
  • 旧系统与文档处理中仍有广泛应用

核心思想

XML 数据 + XSLT 样式表 = 输出(HTML/XML/文本)

数据(内容)与样式(表现)完全分离
样式表本身也是 XML 文档

XSL 语言

XSL 语言

XSL 家族包含三部分,各自负责不同职责。

XSL 三大组成部分

XSLT (XSL Transformations)
  把 XML 转换成其他格式(核心)

XPath (XML Path Language)
  在 XML 中导航和查询的路径语言
  (XSLT 依赖 XPath 定位节点)

XSL-FO (XSL Formatting Objects)
  把 XML 排版为 PDF 等打印格式
  (现在使用较少,由 CSS/PDF工具替代)

XSLT 是什么

XSLT = 声明式语言,描述转换规则
基于模板(template)匹配 XML 节点
规则: 匹配什么 → 输出什么

<xsl:template match="/">
  <html>
    <body>
      <xsl:value-of select="/book/title"/>
    </body>
  </html>
</xsl:template>

XSL 样式表结构

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    ...转换规则...
  </xsl:template>

</xsl:stylesheet>

XSL vs CSS

CSS: 给 HTML 加样式(展示)
XSLT: 转换 XML 结构(重组内容)
XSL 可以做 CSS 做不到的结构转换

XSLT 简介

XSLT 简介

XSLT 把 XML 文档转换为另一个文档,由 W3C 制定标准。

转换过程

输入: XML 文档 + XSLT 样式表
处理: XSLT 处理器遍历 XML 节点,按模板规则输出
输出: HTML / 文本 / 其他 XML

最简单的转换

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <html>
      <body>
        <h2>我的图书收藏</h2>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

结合 XML 数据

XML 数据(catalog.xml):
<catalog>
  <book><title>Web开发</title></book>
  <book><title>数据库基础</title></book>
</catalog>

XSLT 中输出数据:
<xsl:template match="/catalog">
  <ul>
    <xsl:for-each select="book">
      <li><xsl:value-of select="title"/></li>
    </xsl:for-each>
  </ul>
</xsl:template>

输出:
<ul>
  <li>Web开发</li>
  <li>数据库基础</li>
</ul>

特点

声明式(描述要什么,而非怎么做)
纯 XML 语法
平台无关(任何语言都有处理器)

XSLT 浏览器

XSLT 浏览器

现代浏览器内置 XSLT 处理器,可直接在浏览器中应用 XSLT。

XML 关联样式表

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="catalog.xsl"?>
<catalog>
  <book><title>Web开发</title></book>
</catalog>

浏览器打开 XML 文件时自动应用关联的 XSLT,渲染为 HTML。

浏览器兼容

Chrome/Edge/Firefox/Safari 都支持 XSLT 1.0
注意:
  XSLT 2.0/3.0 浏览器不支持(需服务端或库)
  本地 file:// 打开时部分浏览器限制

测试工具:
  xmllint --xinclude / 在线 XSLT 测试器

JavaScript 动态应用

// XSLTProcessor API(浏览器内置)
async function applyXSLT(xmlUrl, xslUrl) {
  const xml = await fetch(xmlUrl).then(r => r.text());
  const xsl = await fetch(xslUrl).then(r => r.text());

  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xml, "application/xml");
  const xslDoc = parser.parseFromString(xsl, "application/xml");

  const processor = new XSLTProcessor();
  processor.importStylesheet(xslDoc);
  const result = processor.transformToFragment(xmlDoc, document);

  document.getElementById("output").appendChild(result);
}

调试工具

xmllint(Linux/macOS)
XMLSpy / Oxygen(专业编辑器)
浏览器开发者工具(检查输出 HTML)

XSLT 转换

XSLT 转换

核心转换机制:模板匹配、内容输出与 XPath 定位。

模板匹配基础

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- 根模板: 匹配文档根 -->
  <xsl:template match="/">
    <html><body>
      <xsl:apply-templates/>
    </body></html>
  </xsl:template>

  <!-- 匹配 book 元素 -->
  <xsl:template match="book">
    <p><xsl:value-of select="title"/></p>
  </xsl:template>

</xsl:stylesheet>

转换流程

1. 处理器从根节点开始
2. 查找匹配的模板(match="/")
3. apply-templates 继续处理子节点
4. 子节点匹配各自模板
5. 生成输出树

(没有匹配模板的节点: 默认只输出文本内容)

命令行转换(xsltproc)

# Linux/macOS 安装 libxslt
sudo apt install libxslt-tools   # Ubuntu
brew install libxslt             # macOS

# 转换
xsltproc catalog.xsl catalog.xml > output.html

# 或 Python(lxml)
from lxml import etree

xml = etree.parse("catalog.xml")
xsl = etree.parse("catalog.xsl")
transform = etree.XSLT(xsl)
result = transform(xml)
print(str(result))

转换输出类型

<xsl:output method="html"/>   <!-- HTML -->
<xsl:output method="xml"/>    <!-- XML(默认) -->
<xsl:output method="text"/>   <!-- 纯文本 -->
<xsl:output method="html" indent="yes"/>  <!-- 缩进 -->

XSLT template 元素

XSLT <template> 元素

template 是 XSLT 的核心:定义节点匹配与输出的规则。

基本用法

<xsl:template match="book">
  <p>这是一本书</p>
</xsl:template>

match 属性: XPath 表达式,匹配哪些节点
命中后执行模板内容

match 表达式示例

<xsl:template match="/">            根节点
<xsl:template match="catalog">       catalog 元素
<xsl:template match="book/title">   book 下的 title
<xsl:template match="//book">      任意层级 book
<xsl:template match="book[@id='1']"> 带属性的 book
<xsl:template match="book[price>50]"> 条件匹配

模板优先级

多个模板匹配同一节点时,按优先级:
  1. 更具体的 match 优先
  2. 相同优先级用 priority 属性指定

<xsl:template match="book" priority="2">
<xsl:template match="*">        <!-- 通用匹配,优先级低 -->

默认模板行为

没有匹配模板时:
  文本节点: 输出文本
  元素节点: 递归处理子节点
  (相当于透传)

可通过 match="text()" 自定义文本处理

命名模板(函数式)

<xsl:template name="header">
  <h1>站点标题</h1>
</xsl:template>

<!-- 调用 -->
<xsl:call-template name="header"/>

<!-- 带参数 -->
<xsl:template name="greet">
  <xsl:param name="name"/>
  <p>你好, <xsl:value-of select="$name"/>!</p>
</xsl:template>
<xsl:call-template name="greet">
  <xsl:with-param name="name" select="'老王'"/>
</xsl:call-template>

XSLT value-of 元素

XSLT <value-of> 元素

value-of 提取节点的值并输出到结果。

基本用法

<!-- XML -->
<book>
  <title>Web 开发</title>
  <price>99</price>
</book>

<!-- XSLT -->
<xsl:template match="book">
  <p>书名: <xsl:value-of select="title"/></p>
  <p>价格: <xsl:value-of select="price"/> 元</p>
</xsl:template>

输出:
  <p>书名: Web 开发</p>
  <p>价格: 99 元</p>

select 表达式

<xsl:value-of select="title"/>        子元素值
<xsl:value-of select="."/>            当前节点文本
<xsl:value-of select="@id"/>          属性值
<xsl:value-of select="/catalog/book/title"/>  绝对路径
<xsl:value-of select="count(book)"/>  函数结果
<xsl:value-of select="string(price)"/> 转字符串

属性输出

<!-- XML: <book id="5">...</book> -->

<xsl:template match="book">
  <div id="book-<xsl:value-of select='@id'/>">
    <xsl:value-of select="title"/>
  </div>
</xsl:template>

// 注意: 属性中嵌入 value-of 写法较特殊
// 更清晰方式:
<xsl:attribute name="id">
  <xsl:value-of select="concat('book-', @id)"/>
</xsl:attribute>

输出字符串常量

<xsl:value-of select="'常量字符串'"/>   <!-- 单引号包字符串 -->
<xsl:value-of select="'100'"/>           <!-- 数字字符串 -->

注意

value-of 只输出第一个匹配节点的值
多个值可用 for-each 或 select 用 xpath 序列(XSLT2)
节点不存在时输出空(不报错)

XSLT for-each 元素

XSLT <for-each> 元素

for-each 遍历节点集合,对每个节点重复执行内容。

基本用法

<!-- XML -->
<catalog>
  <book><title>HTML</title></book>
  <book><title>CSS</title></book>
  <book><title>JS</title></book>
</catalog>

<!-- XSLT: 输出所有书名 -->
<xsl:template match="/">
  <ul>
    <xsl:for-each select="catalog/book">
      <li><xsl:value-of select="title"/></li>
    </xsl:for-each>
  </ul>
</xsl:template>

当前节点上下文

<xsl:for-each select="book">
  <!-- 循环内当前节点是 book -->
  <xsl:value-of select="title"/>    <!-- book/title -->
  <xsl:value-of select="@id"/>      <!-- book 的属性 -->
  <xsl:value-of select="."/>        <!-- book 全部文本 -->
</xsl:for-each>

嵌套 for-each

<xsl:for-each select="catalog">
  <xsl:for-each select="book">
    <p><xsl:value-of select="title"/></p>
  </xsl:for-each>
</xsl:for-each>

筛选与限定

<!-- 只遍历价格大于50的书 -->
<xsl:for-each select="book[price > 50]">

<!-- 前3本 -->
<xsl:for-each select="book[position() <= 3]">

<!-- 遍历属性值匹配的 -->
<xsl:for-each select="book[@category='web']">

for-each vs apply-templates

for-each:      循环体内直接处理(简单场景)
apply-templates: 委托给模板(模块化,推荐复杂场景)

简单重复输出用 for-each 更直观

XSLT sort 元素

XSLT <sort> 元素

sort 对 for-each 或 apply-templates 的结果排序。

基本排序

<xsl:for-each select="book">
  <xsl:sort select="title"/>      <!-- 按书名排序(默认升序) -->
  <p><xsl:value-of select="title"/></p>
</xsl:for-each>

降序排序

<xsl:sort select="price" order="descending"/>  <!-- 价格降序 -->

数值排序

<xsl:sort select="price" data-type="number"/>
<!-- data-type: text(默认)/number/date -->
<!-- 不指定时按字符串排序(100 < 20 问题!) -->

多级排序

<xsl:sort select="category"/>     <!-- 先按分类 -->
<xsl:sort select="price" order="descending" data-type="number"/>
<!-- 再按价格降序 -->

自定义排序键

<xsl:sort select="substring(title, 1, 1)"/>  <!-- 按首字母 -->

完整示例

<xsl:template match="/">
  <table>
    <xsl:for-each select="catalog/book">
      <xsl:sort select="price" data-type="number"
               order="descending"/>
      <tr>
        <td><xsl:value-of select="title"/></td>
        <td><xsl:value-of select="price"/></td>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>

注意

sort 必须是 for-each/apply-templates 的第一个子元素
排序只在循环内部生效

XSLT if 元素

XSLT <if> 元素

if 根据条件决定是否输出内容。

基本用法

<xsl:if test="price > 50">
  <p>这是一本高价书</p>
</xsl:if>

test: 条件表达式(布尔),为真时执行

完整示例

<xsl:for-each select="book">
  <p>
    <xsl:value-of select="title"/>
    <xsl:if test="price > 100">
      <b>(高价)</b>
    </xsl:if>
  </p>
</xsl:for-each>

条件表达式

price > 50             数值比较
@category = 'web'      属性等于
title = 'HTML'         元素文本等于
price > 50 and price < 100  与
@web = 'true' or ...   或
not(@hidden)           取反
position() = 1         第一个
count(book) > 3        函数结果

特殊字符转义:
  >  >    <  <
  & &    "  "

判断节点存在

<xsl:if test="author">     <!-- 存在 author 子元素 -->
<xsl:if test="not(author)">  <!-- 不存在 -->
<xsl:if test="@id">          <!-- 有 id 属性 -->

if 的局限

if 没有 else!
多分支用 choose(见下一章)
if 只控制自身内容输出

XSLT choose 元素

XSLT <choose> 元素

choose-when-otherwise 实现 if-else 多分支逻辑。

基本结构

<xsl:choose>
  <xsl:when test="price > 100">
    <p>高价书</p>
  </xsl:when>
  <xsl:when test="price > 50">
    <p>中价书</p>
  </xsl:when>
  <xsl:otherwise>
    <p>低价书</p>
  </xsl:otherwise>
</xsl:choose>

规则:
  when 从上到下匹配第一个为真的
  otherwise 相当于 else(可选)
  都不满足且无 otherwise 则无输出

示例: 根据属性输出

<xsl:template match="book">
  <xsl:choose>
    <xsl:when test="@category='web'">
      <span class="web">前端</span>
    </xsl:when>
    <xsl:when test="@category='db'">
      <span class="db">数据库</span>
    </xsl:when>
    <xsl:otherwise>
      <span>其他</span>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

复杂条件

<xsl:when test="price > 50 and inStock='true'">

choose 嵌套

<xsl:choose>
  <xsl:when test="a">
    <xsl:choose>...</xsl:choose>  <!-- 嵌套 -->
  </xsl:when>
</xsl:choose>

if vs choose

if:       单个条件,无 else
choose:   多分支 if-else 完整结构
两个条件以上或需要 else 时用 choose

XSLT apply-templates 元素

XSLT <apply-templates> 元素

apply-templates 是模板驱动的核心:把处理权交给匹配的模板。

基本机制

<xsl:template match="/">
  <html><body>
    <xsl:apply-templates/>   <!-- 处理所有子节点 -->
  </body></html>
</xsl:template>

<xsl:template match="book">
  <p><xsl:value-of select="title"/></p>
</xsl:template>

流程:
  根模板 apply-templates
  → 子节点(book)自动匹配到对应模板
  → 各模板输出自己的内容

指定处理节点

<xsl:apply-templates select="book"/>        只处理 book
<xsl:apply-templates select="book/title"/>  处理特定元素
<xsl:apply-templates select="@*"/>          处理属性
<xsl:apply-templates select="text()"/>      处理文本

带参数调用

<xsl:apply-templates select="book">
  <xsl:with-param name="highlight" select="'true'"/>
</xsl:apply-templates>

<xsl:template match="book">
  <xsl:param name="highlight"/>
  <p class="{@id}">...</p>
</xsl:template>

模板模式(mode)

同一节点可被不同模板处理(按 mode 区分):
<xsl:template match="book">             <!-- 默认 -->
<xsl:template match="book" mode="short"> <!-- 简短版 -->

<xsl:apply-templates select="book" mode="short"/>

for-each vs apply-templates

for-each:        手动循环,代码集中
apply-templates: 自动分发,模板可复用、易扩展
复杂/可扩展项目推荐 apply-templates

XSLT import 元素

XSLT <import> 元素

import 引入其他样式表,实现样式表复用与覆盖。

导入样式表

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:import href="common.xsl"/>   <!-- 必须位于最前 -->

  <!-- 本文件模板优先于导入的 -->
  <xsl:template match="book">
    <p>自定义版: <xsl:value-of select="title"/></p>
  </xsl:template>
</xsl:stylesheet>

优先级规则

导入的模板优先级低
本文件的模板覆盖导入的同名模板
多个导入: 后导入的优先(import 顺序)

覆盖后可调用原模板:
<xsl:apply-imports/>   <!-- 调用被覆盖的导入模板 -->

include vs import

include: 内容合并,模板平等(冲突报错)
import:  引入且可被覆盖(推荐,类似继承)

<xsl:include href="header.xsl"/>

应用场景

公共模板库(页头/页脚/导航)
主题定制(基础样式表 + 覆盖)
多站点共享转换逻辑
版本化样式表

XSLT 样式

XSLT 样式

XSLT 输出 HTML 时配合 CSS 控制展示效果。

输出中加 CSS

<xsl:template match="/">
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="style.css"/>
    </head>
    <body>...</body>
  </html>
</xsl:template>

条件加类名

<xsl:template match="book">
  <p>
    <xsl:attribute name="class">
      <xsl:choose>
        <xsl:when test="price > 100">expensive</xsl:when>
        <xsl:otherwise>normal</xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:value-of select="title"/>
  </p>
</xsl:template>

输出: <p class="expensive">...</p>

行内样式简写

<p style="color: {color}">
<!-- {表达式} 在大括号中求值 -->

<p class="{@category}">   <!-- 属性值做类名 -->

生成表格样式

<table border="1">
  <xsl:for-each select="book">
    <xsl:sort select="title"/>
    <tr>
      <td><xsl:value-of select="title"/></td>
      <td align="right"><xsl:value-of select="price"/></td>
    </tr>
  </xsl:for-each>
</table>

注意

XSLT 负责结构,CSS 负责视觉
输出 HTML 时注意转义:
  文本内容用 <xsl:value-of> 自动转义
  需要输出原始 HTML 用 disable-output-escaping

XSLT 客户端应用

XSLT 客户端应用

在浏览器端应用 XSLT,把 XML 渲染为 HTML 页面。

1. XML 关联 XSL 文件

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="catalog.xsl"?>
<catalog>...</catalog>

直接浏览器打开 XML 文件即可看到转换结果。

2. JavaScript 动态转换

async function transformXml(xmlUrl, xslUrl, targetId) {
  const [xmlText, xslText] = await Promise.all([
    fetch(xmlUrl).then(r => r.text()),
    fetch(xslUrl).then(r => r.text()),
  ]);

  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(xmlText, "text/xml");
  const xslDoc = parser.parseFromString(xslText, "text/xml");

  if (parser.parseFromString("", "text/xml").getElementsByTagName("parsererror").length) {
    console.error("XML 解析错误");
    return;
  }

  const xsltProc = new XSLTProcessor();
  xsltProc.importStylesheet(xslDoc);
  const resultDoc = xsltProc.transformToDocument(xmlDoc);

  document.getElementById(targetId).innerHTML =
    new XMLSerializer().serializeToString(resultDoc.documentElement);
}

// 使用
transformXml("data.xml", "style.xsl", "content");

3. 优缺点

优点: 数据与展示分离,样式表可复用
     无需服务端处理,减轻服务器负担
缺点: 浏览器只支持 XSLT 1.0
     复杂转换逻辑难以调试
     现代前端多用 JS 模板引擎替代

4. 何时使用

静态 XML 数据展示
XML 文档预览
老系统兼容
学习 XSLT 场景

XSLT 服务端应用

XSLT 服务端应用

在服务端完成 XSLT 转换,输出最终 HTML 给浏览器。

Python + lxml

from lxml import etree

def transform(xml_file, xsl_file):
    xml = etree.parse(xml_file)
    xsl = etree.parse(xsl_file)
    transform = etree.XSLT(xsl)
    result = transform(xml)
    return str(result)

# Flask 示例
from flask import Flask, Response

app = Flask(__name__)

@app.route("/catalog")
def catalog():
    html = transform("catalog.xml", "catalog.xsl")
    return Response(html, mimetype="text/html")

Java + JAXP

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class XsltDemo {
    public static void main(String[] args) throws Exception {
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(
            new StreamSource("catalog.xsl"));
        transformer.transform(
            new StreamSource("catalog.xml"),
            new StreamResult("catalog.html"));
    }
}

Node.js + xslt-processor

npm install xslt-processor

const { xsltProcess, xmlParse } = require("xslt-processor");

const xml = xmlParse(fs.readFileSync("catalog.xml", "utf-8"));
const xsl = xmlParse(fs.readFileSync("catalog.xsl", "utf-8"));
const html = xsltProcess(xml, xsl);
console.log(html);

服务端 XSLT 优势

支持 XSLT 1.0-3.0 全部特性
数据缓存与性能可控
统一转换逻辑(客户端不感知)
适合: 内容管理、报表生成、数据交换

PHP 示例

<?php
$xml = new DOMDocument();
$xml->load("catalog.xml");

$xsl = new DOMDocument();
$xsl->load("catalog.xsl");

$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);
echo $proc->transformToXML($xml);
?>

XSLT 与 XPath

XSLT 与 XPath

XPath 是 XSLT 的定位语言,掌握常用 XPath 是写 XSLT 的前提。

XPath 基础

/catalog           根下的 catalog
/catalog/book      catalog 下的 book
book/title         book 下的 title
//book             文档中任意 book
//@id              任意 id 属性
./title            当前节点下的 title
../price           父节点的 price

谓词(筛选)

book[1]                第一个 book
book[last()]           最后一个
book[position() < 3]   前两个
book[@id='5']          id 属性为 5
book[price > 50]       价格大于50
book[title='HTML']     title 为 HTML
book[@category and price]  同时有属性与子元素

XPath 函数

text()      取文本节点
count(book) 数量
string(.)   转字符串
concat(a,b) 连接
contains(title,'Web')   包含
starts-with(@id,'b')    开头
normalize-space(title)  去空白
substring(title,1,3)    子串
translate(text,'abc','ABC') 替换字符

轴(Axes)

child::      子节点(默认)
parent::     父节点
ancestor::   祖先节点
descendant:: 后代节点
following-sibling::  后续兄弟
preceding-sibling::  前兄弟

// 常用简写:
. 当前节点  .. 父节点  @ 属性

在 XSLT 中的使用

<xsl:value-of select="//book[2]/title"/>
<xsl:if test="contains(title, '教程')">
<xsl:for-each select="book[price > 30]">

调试 XPath

浏览器 DevTools: $x("//book")
Python: lxml xpath()
命令行: xmllint --xpath '//book' catalog.xml

XSLT 变量与参数

XSLT 变量与参数

variable 与 param 定义可复用的值。

变量(xsl:variable)

<!-- 定义 -->
<xsl:variable name="title" select="'Web 开发'"/>
<xsl:variable name="maxPrice" select="100"/>
<xsl:variable name="bookCount" select="count(/catalog/book)"/>

<!-- 使用($ 引用) -->
<p><xsl:value-of select="$title"/></p>
<xsl:if test="price < $maxPrice">

<!-- 变量值也可由内容构造 -->
<xsl:variable name="greeting">
  <b>欢迎访问!</b>
</xsl:variable>

变量作用域

变量只在定义它的模板内可见
<xsl:variable> 在同一层级内有效
(类似局部变量)

全局变量: 定义在 stylesheet 顶层,处处可用
<xsl:variable name="appName" select="'我的应用'"/>

参数(xsl:param)

<!-- 模板参数 -->
<xsl:template name="item">
  <xsl:param name="label"/>               <!-- 可默认值 -->
  <xsl:param name="value" select="'N/A'"/>
  <p><xsl:value-of select="$label"/>: <xsl:value-of select="$value"/></p>
</xsl:template>

<xsl:call-template name="item">
  <xsl:with-param name="label" select="'价格'"/>
  <xsl:with-param name="value" select="price"/>
</xsl:call-template>

顶层参数(外部传入)

<xsl:param name="mode"/>   <!-- 顶层定义 -->

// xsltproc 传入
xsltproc --stringparam mode dark catalog.xsl catalog.xml

// Python
transform = etree.XSLT(xsl)
result = transform(xml, mode=etree.XSLT.strparam("dark"))

变量 vs 参数

variable: 内部定义的值
param:    外部/调用方传入的值(可设默认)
两者都是不可变(类似常量)

XSLT 高级特性

XSLT 高级特性

XSLT 1.0 之外的扩展能力与技巧。

常用函数

<xsl:value-of select="format-number(price, '#,##0.00')"/>
<!-- 数字格式化: 1,234.56 -->

<xsl:value-of select="sum(//book/price)"/>
<!-- 求和 -->

<xsl:value-of select="string-length(title)"/>
<!-- 长度 -->

<xsl:value-of select="normalize-space(text())"/>
<!-- 清理空白 -->

输出转义控制

<!-- 输出原始 HTML(慎用) -->
<xsl:value-of select="content" disable-output-escaping="yes"/>

<!-- 普通 value-of 会转义 < > & -->

消息与调试

<xsl:message terminate="yes">错误: 缺少必要数据</xsl:message>
<!-- terminate=yes 终止转换 -->
<!-- 默认打印警告继续执行 -->

文本输出

<xsl:text>静态文本</xsl:text>   <!-- 保留空白 -->
<xsl:text disable-output-escaping="yes">&lt;br/&gt;</xsl:text>

XSLT 2.0+ 增强(服务端)

分组: <xsl:for-each-group>
多输出: <xsl:result-document>
正则: analyze-string
多个输入/输出文档
日期与正则类型
更好的类型系统(XSD)

(XSLT 2.0/3.0 需 Saxon 等处理器)

Saxon(高级处理器)

# Java
java -jar saxon-he.jar -s:catalog.xml -xsl:catalog.xsl -o:out.html

# Python(SaxonC)
# pip install saxonche

XSLT 总结与资源

XSLT 总结与资源

恭喜完成 XSLT 教程!回顾知识体系与学习资源。

知识体系回顾

  • XSL 家族:XSLT(转换)+ XPath(定位)+ XSL-FO(排版)
  • 模板机制:template 匹配节点,apply-templates 分发
  • 取值输出:value-of、for-each、文本与属性
  • 流程控制:if、choose-when-otherwise、sort
  • 复用:命名模板、import/include、变量与参数
  • 定位:XPath 路径、谓词、函数、轴
  • 应用:客户端(XSLTProcessor)、服务端(xsltproc/lxml/Saxon)

核心思想

1. 数据与展示分离
2. 声明式编程(描述规则,处理器执行)
3. 模板驱动(节点 → 输出)
4. XPath 是选择数据的语言

学习资源

W3C 规范: w3.org/TR/xslt
W3Schools XSLT 教程(中文版)
XPath 教程: w3schools.com/xml/xpath_intro.asp
在线练习: 免费在线 XSLT 测试器

工具推荐

xsltproc      命令行(快速测试)
Saxon         高级处理器(XSLT 2.0/3.0)
Oxygen XML    专业编辑器
XMLSpy        可视化调试
浏览器 DevTools  检查输出

现代视角

现代前端多用 JS 模板/框架渲染数据
但 XSLT 仍是 XML 标准转换工具:
  文档发布流水线
  数据交换格式转换
  旧系统维护
  学习声明式转换思想

掌握 XSLT 模板与 XPath,你就理解了 XML 生态中最强大的转换机制,这也会加深你对数据-表现分离架构的理解。

第 1 / 20 节