XSLT 实例、元素与转换:从入门到实战
1. 引言
XSLT(可扩展样式表语言转换)是一种用于将 XML 文档转换为其他格式(如 HTML、文本或其他 XML)的语言。它通过 XSLT 样式表定义转换规则,将源 XML 树映射为目标输出树。本文将通过丰富的代码实例,系统讲解 XSLT 的核心元素、转换机制和实战应用。
2. XSLT 基础概念
XSLT 样式表本身是一个 XML 文档,根元素为<xsl:stylesheet>或<xsl:transform>。它通过 XPath 表达式定位 XML 节点,并使用模板规则描述如何转换这些节点。
一个最简单的 XSLT 样式表结构如下:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <h2>Hello, XSLT!</h2> </body> </html> </xsl:template> </xsl:stylesheet>上述样式表匹配文档根节点,输出一个简单的 HTML 页面。下面我们通过一个完整的实例来理解 XSLT 的工作流程。
3. XSLT 实例:图书列表转换
假设我们有一个描述图书信息的 XML 文档,希望通过 XSLT 将其转换为 HTML 表格展示。
3.1 源 XML 文档
<?xml version="1.0" encoding="UTF-8"?> <bookstore> <book category="编程"> <title lang="zh">XML 入门与实践</title> <author>张三</author> <price>59.00</price> </book> <book category="数据库"> <title lang="zh">SQL 高级查询</title> <author>李四</author> <price>79.00</price> </book> <book category="编程"> <title lang="en">XSLT Cookbook</title> <author>王五</author> <price>99.00</price> </book> </bookstore>3.2 XSLT 样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head> <title>图书列表</title> </head> <body> <h2>图书信息一览</h2> <table border="1"> <tr> <th>书名</th> <th>作者</th> <th>价格</th> <th>分类</th> </tr> <xsl:for-each select="bookstore/book"> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="author"/></td> <td><xsl:value-of select="price"/></td> <td><xsl:value-of select="@category"/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>3.3 转换结果
上述样式表通过<xsl:for-each>遍历所有book元素,并使用<xsl:value-of>提取子元素和属性的值,最终生成如下 HTML 表格:
<html> <head> <title>图书列表</title> </head> <body> <h2>图书信息一览</h2> <table border="1"> <tr> <th>书名</th> <th>作者</th> <th>价格</th> <th>分类</th> </tr> <tr> <td>XML 入门与实践</td> <td>张三</td> <td>59.00</td> <td>编程</td> </tr> <tr> <td>SQL 高级查询</td> <td>李四</td> <td>79.00</td> <td>数据库</td> </tr> <tr> <td>XSLT Cookbook</td> <td>王五</td> <td>99.00</td> <td>编程</td> </tr> </table> </body> </html>4. XSLT 核心元素详解
XSLT 提供了丰富的元素用于构建转换规则。下面逐一介绍最常用的核心元素,并给出可运行的代码实例。
4.1 xsl:template 与 xsl:apply-templates
<xsl:template>定义转换规则,<xsl:apply-templates>将模板应用于匹配的节点。这是 XSLT 最核心的递归处理机制。
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <xsl:apply-templates select="bookstore/book"/> </body> </html> </xsl:template> <xsl:template match="book"> <p> <strong><xsl:value-of select="title"/></strong> 作者:<xsl:value-of select="author"/> 价格:<xsl:value-of select="price"/> </p> </xsl:template> </xsl:stylesheet>当根模板匹配到bookstore/book节点时,会自动调用匹配book的模板,实现节点级递归处理。
4.2 xsl:value-of 与 xsl:text
<xsl:value-of>用于提取节点或表达式的字符串值;<xsl:text>用于输出纯文本内容,可精确控制空白字符。
<xsl:template match="book"> <p> <xsl:text>书名:</xsl:text> <xsl:value-of select="title"/> <xsl:text>(作者:</xsl:text> <xsl:value-of select="author"/> <xsl:text>)</xsl:text> </p> </xsl:template>4.3 xsl:for-each 与排序
<xsl:for-each>用于循环遍历节点集,可配合<xsl:sort>实现排序输出。
<xsl:template match="/"> <ul> <xsl:for-each select="bookstore/book"> <xsl:sort select="price"><xsl:template match="book"> <p> <xsl:value-of select="title"/> <xsl:if test="price > 80"> (高价图书) </xsl:if> </p> </xsl:template><xsl:template match="book"> <p> <xsl:value-of select="title"/> <xsl:choose> <xsl:when test="price > 80"> (高价图书) </xsl:when> <xsl:when test="price > 60"> (中价图书) </xsl:when> <xsl:otherwise> (低价图书) </xsl:otherwise> </xsl:choose> </p> </xsl:template>4.5 xsl:attribute 与 xsl:element 动态创建
<xsl:attribute>动态添加属性;<xsl:element>动态创建元素,适用于输出结构不固定的场景。
<xsl:template match="book"> <xsl:element name="div"> <xsl:attribute name="class"> <xsl:choose> <xsl:when test="price > 80">high-price</xsl:when> <xsl:otherwise>normal-price</xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:value-of select="title"/> </xsl:element> </xsl:template>4.6 xsl:variable 与 xsl:param 变量和参数
<xsl:variable>定义局部变量;<xsl:param>定义可被外部传入的模板参数。
<xsl:template match="/"> <xsl:variable name="discount" select="0.8"/> <xsl:for-each select="bookstore/book"> <p> <xsl:value-of select="title"/> 折后价:<xsl:value-of select="price * $discount"/> </p> </xsl:for-each> </xsl:template><xsl:template name="book-item"> <xsl:param name="showPrice" select="'true'"/> <p> <xsl:value-of select="title"/> <xsl:if test="$showPrice = 'true'"> (<xsl:value-of select="price"/> 元) </xsl:if> </p> </xsl:template>4.7 xsl:call-template 与命名模板
<xsl:call-template>按名称调用模板,实现代码复用。
<xsl:template match="/"> <html> <body> <xsl:for-each select="bookstore/book"> <xsl:call-template name="book-item"/> </xsl:for-each> </body> </html> </xsl:template> <xsl:template name="book-item"> <p> <xsl:value-of select="title"/> 作者:<xsl:value-of select="author"/> </p> </xsl:template>4.8 xsl:number 自动编号
<xsl:number>为节点自动编号,常用于生成目录或列表序号。
<xsl:template match="book"> <p> <xsl:number value="position()" format="1. "/> <xsl:value-of select="title"/> </p> </xsl:template>4.9 xsl:copy 与 xsl:copy-of 节点复制
<xsl:copy>复制当前节点(不含子节点);<xsl:copy-of>复制节点及其全部子树。
<xsl:template match="book"> <xsl:copy> <xsl:attribute name="source">bookstore</xsl:attribute> <xsl:copy-of select="title"/> </xsl:copy> </xsl:template>4.10 xsl:output 输出格式控制
<xsl:output>声明输出文档的类型、编码和缩进方式。
<xsl:output method="html" encoding="UTF-8" indent="yes"/>常用 method 取值包括xml、html和text。
5. XSLT 转换实战:XML 转 HTML 报表
下面综合运用上述元素,实现一个完整的 XML 转 HTML 报表案例。源数据为员工信息,要求输出带统计信息的报表。
5.1 源 XML
<?xml version="1.0" encoding="UTF-8"?> <company> <department name="研发部"> <employee> <name>赵一</name> <position>高级工程师</position> <salary>25000</salary> </employee> <employee> <name>钱二</name> <position>工程师</position> <salary>18000</salary> </employee> </department> <department name="市场部"> <employee> <name>孙三</name> <position>市场专员</position> <salary>12000</salary> </employee> </department> </company>5.2 XSLT 样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <html> <head> <title>员工报表</title> </head> <body> <h2>公司员工报表</h2> <xsl:apply-templates select="company/department"/> <hr/> <p> <strong>员工总数:</strong> <xsl:value-of select="count(company/department/employee)"/> </p> <p> <strong>平均薪资:</strong> <xsl:value-of select="format-number(sum(company/department/employee/salary) div count(company/department/employee), '¥#,##0.00')"/> </p> </body> </html> </xsl:template> <xsl:template match="department"> <h3><xsl:value-of select="@name"/></h3> <table border="1"> <tr> <th>序号</th> <th>姓名</th> <th>职位</th> <th>薪资</th> </tr> <xsl:for-each select="employee"> <tr> <td><xsl:number value="position()" format="1"/></td> <td><xsl:value-of select="name"/></td> <td><xsl:value-of select="position"/></td> <td><xsl:value-of select="format-number(salary, '¥#,##0')"/></td> </tr> </xsl:for-each> </table> </xsl:template> </xsl:stylesheet>5.3 关键点说明
count()函数统计节点数量。sum()函数对节点集求和。format-number()函数格式化数字为货币样式。<xsl:number>为每行生成序号。
6. XSLT 转换实战:XML 转 XML 数据重组
XSLT 也常用于 XML 到 XML 的结构重组,例如将扁平结构转换为嵌套结构。
6.1 源 XML(扁平结构)
<?xml version="1.0" encoding="UTF-8"?> <orders> <order id="1001" customer="张三" product="笔记本电脑" quantity="1"/> <order id="1002" customer="李四" product="鼠标" quantity="2"/> <order id="1003" customer="张三" product="键盘" quantity="1"/> </orders>6.2 XSLT 样式表(按客户分组)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" encoding="UTF-8" indent="yes"/> <xsl:key name="customer-key" match="order" use="@customer"/> <xsl:template match="/"> <customer-orders> <xsl:for-each select="orders/order[generate-id() = generate-id(key('customer-key', @customer)[1])]"> <xsl:sort select="@customer"/> <customer name="{@customer}"> <xsl:for-each select="key('customer-key', @customer)"> <order id="{@id}" product="{@product}" quantity="{@quantity}"/> </xsl:for-each> </customer> </xsl:for-each> </customer-orders> </xsl:template> </xsl:stylesheet>6.3 转换结果
<?xml version="1.0" encoding="UTF-8"?> <customer-orders> <customer name="张三"> <order id="1001" product="笔记本电脑" quantity="1"/> <order id="1003" product="键盘" quantity="1"/> </customer> <customer name="李四"> <order id="1002" product="鼠标" quantity="2"/> </customer> </customer-orders>这里使用<xsl:key>和generate-id()实现分组,是 XSLT 1.0 中常用的分组技巧。
7. XSLT 转换实战:XML 转纯文本
当输出格式为纯文本时,使用method="text",常用于生成配置文件或日志。
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="UTF-8"/> <xsl:template match="/"> <xsl:text>图书清单 </xsl:text> <xsl:text>==================== </xsl:text> <xsl:for-each select="bookstore/book"> <xsl:value-of select="title"/> <xsl:text> | </xsl:text> <xsl:value-of select="author"/> <xsl:text> | </xsl:text> <xsl:value-of select="price"/> <xsl:text> 元 </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>输出结果为:
图书清单 ==================== XML 入门与实践 | 张三 | 59.00 元 SQL 高级查询 | 李四 | 79.00 元 XSLT Cookbook | 王五 | 99.00 元8. 常见问题与调试技巧
8.1 命名空间处理
当源 XML 使用命名空间时,样式表中必须声明相同的命名空间前缀,并在 XPath 中使用该前缀。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:bk="http://www.example.com/bookstore"> <xsl:template match="/"> <xsl:for-each select="bk:bookstore/bk:book"> <p><xsl:value-of select="bk:title"/></p> </xsl:for-each> </xsl:template> </xsl:stylesheet>8.2 调试建议
- 使用
indent="yes"让输出更易读。 - 先用简单模板验证 XPath 路径是否正确。
- 利用
<xsl:message>输出调试信息到控制台。 - 分步转换:先输出 XML,再转换为 HTML,便于定位问题。
<xsl:template match="book"> <xsl:message>正在处理图书:<xsl:value-of select="title"/></xsl:message> <p><xsl:value-of select="title"/></p> </xsl:template>9. 总结
本文通过丰富的代码实例,系统介绍了 XSLT 的核心元素与转换机制。从最简单的模板匹配,到for-each、choose、variable、key等高级特性,再到 XML 转 HTML、XML 转 XML、XML 转文本三种典型场景,覆盖了 XSLT 开发的主要知识点。掌握这些内容后,读者可以灵活运用 XSLT 完成各类数据转换任务。
