XSLT 输出控制
本章定位 :掌握 XSLT 中控制输出内容的指令——
xsl:value-of(提取值)、xsl:attribute/xsl:element(动态创建属性/元素)、xsl:copy/xsl:copy-of(复制节点)。
定义与作用
前面学的模板和控制结构决定了"处理哪些节点",本节关注"输出什么内容"。XSLT 提供了精确的输出控制指令:
xsl:value-of:提取节点的字符串值,输出到结果树xsl:attribute:在输出元素上动态创建属性xsl:element:动态创建输出元素(元素名来自表达式)xsl:text:精确输出文本(保留空白)xsl:copy:浅复制——复制当前节点但不含子节点和属性xsl:copy-of:深复制——复制当前节点及其所有后代和属性
核心原理:浅复制 vs 深复制
图解释 :xsl:copy 只复制当前节点的标签(不含属性和子节点),需要手动用 xsl:apply-templates 复制子内容。xsl:copy-of 一步到位,完整复制整个子树。
语法/结构要点
| 指令 | 作用 | 示例 |
|---|---|---|
xsl:value-of | 输出节点值 | <xsl:value-of select="title"/> |
xsl:attribute | 动态创建属性 | <xsl:attribute name="href">link</xsl:attribute> |
xsl:element | 动态创建元素 | <xsl:element name="h{level}">heading</xsl:element> |
xsl:text | 精确输出文本 | <xsl:text> </xsl:text>(保留空白) |
xsl:copy | 浅复制当前节点 | <xsl:copy><xsl:apply-templates/></xsl:copy> |
xsl:copy-of | 深复制节点及子树 | <xsl:copy-of select="book"/> |
xsl:comment | 输出注释 | <xsl:comment>生成时间</xsl:comment> |
完整示例:小崔实现 XML→XML 格式升级
场景说明
飞翔科技的后端 小崔 需要把旧版学生 XML 升级为新版格式。变化:元素名 snake_case 改 camelCase、添加 version 属性、移除敏感字段 ssn。
操作前:旧版 XML
<students>
<student_record id="S001">
<full_name>崔志远</full_name>
<major_code>CS</major_code>
<enroll_year>2023</enroll_year>
<ssn>123-45-6789</ssn>
</student_record>
</students>
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" indent="yes"/>
<!-- 根模板:创建新版根元素 -->
<xsl:template match="/">
<xsl:element name="university">
<xsl:attribute name="version">2.0</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<!-- student_record → student -->
<xsl:template match="student_record">
<xsl:element name="student">
<xsl:attribute name="id">
<xsl:value-of select="@id"/>
</xsl:attribute>
<!-- 拷贝所有子元素,但跳过 ssn -->
<xsl:apply-templates select="*[not(self::ssn)]"/>
</xsl:element>
</xsl:template>
<!-- full_name → fullName -->
<xsl:template match="full_name">
<xsl:element name="fullName">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- major_code → majorCode -->
<xsl:template match="major_code">
<xsl:element name="majorCode">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- enroll_year → enrollYear -->
<xsl:template match="enroll_year">
<xsl:element name="enrollYear">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- ssn:直接跳过(不输出任何内容) -->
<xsl:template match="ssn"/>
</xsl:stylesheet>
操作结果:新版 XML
<?xml version="1.0" encoding="UTF-8"?>
<university version="2.0">
<student id="S001">
<fullName>崔志远</fullName>
<majorCode>CS</majorCode>
<enrollYear>2023</enrollYear>
</student>
</university>
小崔完成了三件事:①元素名全部改为 camelCase;②根元素改名为 university 并加 version 属性;③敏感字段 ssn 被静默移除。
易错场景
错误一:xsl:copy 后忘记 apply-templates
<!-- ❌ 只复制了外层标签,子内容丢失 -->
<xsl:template match="book">
<xsl:copy/>
</xsl:template>
<!-- ✅ 浅复制 + 递归处理子节点 -->
<xsl:template match="book">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
错误二:value-of 和 copy-of 混淆
xsl:value-of:输出节点的文本值(去掉所有标签)xsl:copy-of:输出节点的完整 XML(保留所有标签和属性)
面试考点
| 考点 | 参考答案要点 |
|---|---|
| xsl:copy 和 xsl:copy-of 的区别? | copy 浅复制(只复制当前节点标签,不含属性和子节点),copy-of 深复制(含整个子树和属性) |
| xsl:value-of 和 xsl:copy-of 的区别? | value-of 提取字符串值(去标签),copy-of 保留 XML 结构 |
| 如何用 XSLT 实现"删除某字段"? | 为要删除的元素写一个空模板(没有内容),如 <xsl:template match="ssn"/>。这样该元素被匹配但不输出任何内容 |