|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
XSLT(Extensible Stylesheet Language Transformations)是一种用于将XML文档转换为其他格式的强大语言。在当今数据交换和文档处理领域,XML作为一种通用的数据格式被广泛应用,而XSLT则提供了处理和转换这些XML数据的灵活方法。无论是将XML转换为HTML用于网页显示,还是转换为其他XML格式以满足不同系统的需求,XSLT都扮演着至关重要的角色。
本文将全面介绍XSLT的基础语法、核心概念以及实际应用技巧,帮助读者掌握这一强大的技术,轻松实现XML数据的格式化与转换。通过丰富的示例和详细的解释,即使是初学者也能逐步理解并应用XSLT解决实际问题。
XSLT基础概念
什么是XSLT
XSLT是W3C推荐的一种标准,它属于XSL(Extensible Stylesheet Language)家族的一部分。XSLT的主要功能是将XML文档转换为其他格式的文档,如HTML、XML、文本或其他格式。这种转换是通过应用一系列模板规则来实现的,这些规则定义了如何处理源XML文档中的各个部分。
XSLT与XML的关系
XML(eXtensible Markup Language)是一种用于存储和传输数据的标记语言,它具有自描述性和平台无关性的特点。然而,XML本身只关注数据的结构和内容,而不涉及数据的显示和格式。这就是XSLT发挥作用的地方——它能够读取XML数据,并根据预定义的规则将其转换为所需的格式。
一个典型的XSLT处理过程包括三个主要组件:
1. 源XML文档:包含需要转换的数据
2. XSLT样式表:包含转换规则和模板
3. 结果文档:转换后的输出
XSLT处理器
XSLT处理器是执行XSLT转换的软件组件。它读取源XML文档和XSLT样式表,应用样式表中定义的规则,生成结果文档。常见的XSLT处理器包括:
• Saxon:功能强大的Java实现的XSLT处理器
• Xalan:Apache软件基金会的XSLT处理器
• MSXML:微软的XML处理器,内置在Windows和Internet Explorer中
• libxslt:开源的XSLT处理器,是GNOME项目的一部分
XSLT基础语法
XSLT文档结构
一个基本的XSLT文档结构如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <!-- XSLT模板和规则在这里定义 -->
- </xsl:stylesheet>
复制代码
或者使用XSLT 2.0或更高版本:
- <?xml version="1.0" encoding="UTF-8"?>
- <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <!-- XSLT模板和规则在这里定义 -->
- </xsl:stylesheet>
复制代码
模板规则
模板是XSLT的核心概念,它定义了如何处理XML文档中的特定节点。基本的模板语法如下:
- <xsl:template match="pattern">
- <!-- 模板内容 -->
- </xsl:template>
复制代码
其中,match属性指定了该模板应用的XML节点模式。例如:
- <xsl:template match="/">
- <!-- 处理文档根节点的模板 -->
- </xsl:template>
- <xsl:template match="book">
- <!-- 处理book元素的模板 -->
- </xsl:template>
复制代码
XPath表达式
XPath是用于在XML文档中定位节点的语言,它在XSLT中扮演着重要角色。通过XPath,我们可以选择XML文档中的特定节点或节点集。以下是一些常用的XPath表达式示例:
• /:选择文档根节点
• *:选择所有元素节点
• @*:选择所有属性节点
• node():选择所有节点(元素、文本、注释、处理指令等)
• text():选择文本节点
• .:选择当前节点
• ..:选择当前节点的父节点
• //:选择文档中所有匹配的节点,无论它们在什么位置
• book:选择所有book元素
• book/title:选择所有book元素的子元素title
• book[@id]:选择所有具有id属性的book元素
• book[@id='bk101']:选择id属性值为’bk101’的book元素
输出指令
XSLT允许我们通过xsl:output指令指定输出文档的格式和属性:
- <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
复制代码
常用的method属性值包括:
• xml:输出为XML格式(默认)
• html:输出为HTML格式
• text:输出为纯文本格式
XSLT核心元素详解
xsl:template
xsl:template是XSLT中最基本的元素,用于定义处理特定节点的模板规则。它的match属性指定了该模板应用的节点模式。
示例:
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book List</h1>
- <xsl:apply-templates select="catalog/book"/>
- </body>
- </html>
- </xsl:template>
- <xsl:template match="book">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <p>Author: <xsl:value-of select="author"/></p>
- <p>Price: <xsl:value-of select="price"/></p>
- </div>
- </xsl:template>
复制代码
xsl:value-of
xsl:value-of用于提取并输出选定节点的值。它的select属性指定要提取的节点。
示例:
- <xsl:template match="book">
- <p>Title: <xsl:value-of select="title"/></p>
- <p>Author: <xsl:value-of select="author"/></p>
- </xsl:template>
复制代码
xsl:for-each
xsl:for-each用于循环处理节点集中的每个节点。它的select属性指定要循环的节点集。
示例:
- <xsl:template match="/">
- <ul>
- <xsl:for-each select="catalog/book">
- <li><xsl:value-of select="title"/> by <xsl:value-of select="author"/></li>
- </xsl:for-each>
- </ul>
- </xsl:template>
复制代码
xsl:if
xsl:if用于条件处理,当指定的条件为真时,执行其内容。它的test属性指定要测试的条件。
示例:
- <xsl:template match="book">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <xsl:if test="price > 50">
- <p class="expensive">This book is expensive!</p>
- </xsl:if>
- </div>
- </xsl:template>
复制代码
xsl:choose, xsl:when, xsl:otherwise
这组元素用于多条件判断,类似于编程语言中的switch-case语句。
示例:
- <xsl:template match="book">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <xsl:choose>
- <xsl:when test="price < 20">
- <p class="cheap">This book is cheap!</p>
- </xsl:when>
- <xsl:when test="price >= 20 and price <= 50">
- <p class="moderate">This book is moderately priced.</p>
- </xsl:when>
- <xsl:otherwise>
- <p class="expensive">This book is expensive!</p>
- </xsl:otherwise>
- </xsl:choose>
- </div>
- </xsl:template>
复制代码
xsl:sort
xsl:sort用于在xsl:for-each或xsl:apply-templates中对节点进行排序。
示例:
- <xsl:template match="/">
- <ul>
- <xsl:for-each select="catalog/book">
- <xsl:sort select="title" order="ascending"/>
- <li><xsl:value-of select="title"/> by <xsl:value-of select="author"/></li>
- </xsl:for-each>
- </ul>
- </xsl:template>
复制代码
xsl:variable 和 xsl:param
xsl:variable用于定义变量,xsl:param用于定义参数。变量一旦定义就不能更改,而参数可以在模板调用时传递值。
示例:
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:variable name="currency" select="'USD'"/>
-
- <xsl:template match="/">
- <xsl:apply-templates select="catalog/book">
- <xsl:with-param name="discount" select="0.1"/>
- </xsl:apply-templates>
- </xsl:template>
-
- <xsl:template match="book">
- <xsl:param name="discount" select="0"/>
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <p>Price: <xsl:value-of select="price * (1 - $discount)"/> <xsl:value-of select="$currency"/></p>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
xsl:apply-templates
xsl:apply-templates用于指示XSLT处理器应用其他模板来处理当前节点的子节点。它的select属性指定要处理的节点集。
示例:
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book List</h1>
- <xsl:apply-templates select="catalog/book"/>
- </body>
- </html>
- </xsl:template>
- <xsl:template match="book">
- <div>
- <xsl:apply-templates select="title"/>
- <xsl:apply-templates select="author"/>
- <xsl:apply-templates select="price"/>
- </div>
- </xsl:template>
- <xsl:template match="title">
- <h2><xsl:value-of select="."/></h2>
- </xsl:template>
- <xsl:template match="author">
- <p>Author: <xsl:value-of select="."/></p>
- </xsl:template>
- <xsl:template match="price">
- <p>Price: <xsl:value-of select="."/></p>
- </xsl:template>
复制代码
xsl:attribute
xsl:attribute用于向输出元素添加属性。
示例:
- <xsl:template match="book">
- <div>
- <xsl:attribute name="id">
- <xsl:value-of select="@id"/>
- </xsl:attribute>
- <h2><xsl:value-of select="title"/></h2>
- <p>Author: <xsl:value-of select="author"/></p>
- </div>
- </xsl:template>
复制代码
xsl:copy 和 xsl:copy-of
xsl:copy用于复制当前节点(不包括子节点和属性),而xsl:copy-of用于复制当前节点及其所有子节点和属性。
示例:
- <xsl:template match="book">
- <xsl:copy>
- <xsl:copy-of select="@*"/>
- <title><xsl:value-of select="title"/></title>
- <author><xsl:value-of select="author"/></author>
- </xsl:copy>
- </xsl:template>
复制代码
XSLT高级功能
条件处理
除了前面介绍的xsl:if和xsl:choose,XSLT还提供了其他条件处理方式,如使用XPath函数进行条件判断。
示例:
- <xsl:template match="book">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <p>Genre:
- <xsl:value-of select="concat(genre,
- if (genre = 'Fantasy') then ' (Fiction)'
- else if (genre = 'Biography') then ' (Non-Fiction)'
- else '')"/>
- </p>
- </div>
- </xsl:template>
复制代码
循环处理
除了xsl:for-each,XSLT还提供了递归模板调用的方式来实现循环处理,这在处理复杂结构或需要特定迭代逻辑时特别有用。
示例:
- <xsl:template name="generate-list">
- <xsl:param name="items"/>
- <xsl:param name="index" select="1"/>
-
- <xsl:if test="$index <= count($items)">
- <li>
- <xsl:value-of select="$items[$index]"/>
- </li>
- <xsl:call-template name="generate-list">
- <xsl:with-param name="items" select="$items"/>
- <xsl:with-param name="index" select="$index + 1"/>
- </xsl:call-template>
- </xsl:if>
- </xsl:template>
复制代码
变量和参数的高级用法
XSLT中的变量和参数可以存储各种类型的值,包括节点集、字符串、数字和布尔值。它们还可以用于构建复杂的表达式和逻辑。
示例:
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:variable name="books-by-genre" select="catalog/book[genre = 'Fantasy']"/>
-
- <xsl:template match="/">
- <html>
- <body>
- <h1>Fantasy Books</h1>
- <xsl:call-template name="display-books">
- <xsl:with-param name="books" select="$books-by-genre"/>
- <xsl:with-param name="show-price" select="true()"/>
- </xsl:call-template>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template name="display-books">
- <xsl:param name="books"/>
- <xsl:param name="show-price" select="false()"/>
-
- <xsl:for-each select="$books">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <p>Author: <xsl:value-of select="author"/></p>
- <xsl:if test="$show-price">
- <p>Price: <xsl:value-of select="price"/></p>
- </xsl:if>
- </div>
- </xsl:for-each>
- </xsl:template>
- </xsl:stylesheet>
复制代码
模式和模式匹配
XSLT允许为同一个元素定义多个模板,通过模式(mode)来区分它们。这在需要以不同方式处理同一元素时非常有用。
示例:
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book List - Summary</h1>
- <xsl:apply-templates select="catalog/book" mode="summary"/>
-
- <h1>Book List - Details</h1>
- <xsl:apply-templates select="catalog/book" mode="detail"/>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="book" mode="summary">
- <p><xsl:value-of select="title"/> by <xsl:value-of select="author"/></p>
- </xsl:template>
-
- <xsl:template match="book" mode="detail">
- <div>
- <h2><xsl:value-of select="title"/></h2>
- <p>Author: <xsl:value-of select="author"/></p>
- <p>Genre: <xsl:value-of select="genre"/></p>
- <p>Price: <xsl:value-of select="price"/></p>
- <p>Description: <xsl:value-of select="description"/></p>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
键和索引
XSLT提供了xsl:key元素来定义键,用于高效地查找和引用节点。这在处理大型XML文档或需要频繁引用特定节点时特别有用。
示例:
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:key name="book-by-id" match="book" use="@id"/>
-
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book References</h1>
- <xsl:for-each select="catalog/reference">
- <xsl:variable name="book-id" select="@book-id"/>
- <p>
- Reference: <xsl:value-of select="text()"/>
- <br/>
- Book: <xsl:value-of select="key('book-by-id', $book-id)/title"/>
- </p>
- </xsl:for-each>
- </body>
- </html>
- </xsl:template>
- </xsl:stylesheet>
复制代码
数字和日期处理
XSLT提供了丰富的函数来处理数字和日期,包括格式化、计算和转换等操作。
示例:
- <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book Statistics</h1>
- <p>Total books: <xsl:value-of select="count(catalog/book)"/></p>
- <p>Average price: <xsl:value-of select="format-number(avg(catalog/book/price), '$#.00')"/></p>
- <p>Most expensive book: <xsl:value-of select="max(catalog/book/price)"/></p>
- <p>Current date: <xsl:value-of select="format-date(current-date(), '[D01] [MNn] [Y0001]')"/></p>
- </body>
- </html>
- </xsl:template>
- </xsl:stylesheet>
复制代码
字符串处理
XSLT提供了多种字符串处理函数,如连接、分割、替换和格式化等。
示例:
- <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:template match="/">
- <html>
- <body>
- <h1>Book Titles</h1>
- <xsl:for-each select="catalog/book">
- <p>
- Original: <xsl:value-of select="title"/>
- <br/>
- Upper case: <xsl:value-of select="upper-case(title)"/>
- <br/>
- Length: <xsl:value-of select="string-length(title)"/>
- <br/>
- First 10 characters: <xsl:value-of select="substring(title, 1, 10)"/>
- </p>
- </xsl:for-each>
- </body>
- </html>
- </xsl:template>
- </xsl:stylesheet>
复制代码
实际应用案例
案例1:XML到HTML的转换
假设我们有一个包含书籍信息的XML文档,我们想要将其转换为HTML格式以便在网页上显示。
源XML文档(books.xml):
- <?xml version="1.0" encoding="UTF-8"?>
- <catalog>
- <book id="bk101">
- <title>XML Developer's Guide</title>
- <author>Gambardella, Matthew</author>
- <genre>Computer</genre>
- <price>44.95</price>
- <publish_date>2000-10-01</publish_date>
- <description>An in-depth look at creating applications with XML.</description>
- </book>
- <book id="bk102">
- <title>Midnight Rain</title>
- <author>Ralls, Kim</author>
- <genre>Fantasy</genre>
- <price>5.95</price>
- <publish_date>2000-12-16</publish_date>
- <description>A former architect battles corporate zombies.</description>
- </book>
- <book id="bk103">
- <title>Maeve Ascendant</title>
- <author>Corets, Eva</author>
- <genre>Fantasy</genre>
- <price>5.95</price>
- <publish_date>2000-11-17</publish_date>
- <description>After the collapse of a nanotechnology society, the young survivors band together.</description>
- </book>
- </catalog>
复制代码
XSLT样式表(books-to-html.xsl):
- <?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" indent="yes" encoding="UTF-8"/>
-
- <xsl:template match="/">
- <html>
- <head>
- <title>Book Catalog</title>
- <style>
- body { font-family: Arial, sans-serif; }
- .book { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; }
- .title { font-weight: bold; font-size: 1.2em; color: #0066cc; }
- .author { font-style: italic; }
- .price { color: #009900; font-weight: bold; }
- .genre { background-color: #f0f0f0; padding: 2px 5px; border-radius: 3px; }
- </style>
- </head>
- <body>
- <h1>Book Catalog</h1>
- <xsl:apply-templates select="catalog/book"/>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="book">
- <div class="book">
- <div class="title"><xsl:value-of select="title"/></div>
- <div class="author">by <xsl:value-of select="author"/></div>
- <div>Genre: <span class="genre"><xsl:value-of select="genre"/></span></div>
- <div class="price">Price: $<xsl:value-of select="price"/></div>
- <div>Published: <xsl:value-of select="publish_date"/></div>
- <div><xsl:value-of select="description"/></div>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
转换后的HTML输出:
- <html>
- <head>
- <title>Book Catalog</title>
- <style>
- body { font-family: Arial, sans-serif; }
- .book { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; }
- .title { font-weight: bold; font-size: 1.2em; color: #0066cc; }
- .author { font-style: italic; }
- .price { color: #009900; font-weight: bold; }
- .genre { background-color: #f0f0f0; padding: 2px 5px; border-radius: 3px; }
- </style>
- </head>
- <body>
- <h1>Book Catalog</h1>
- <div class="book">
- <div class="title">XML Developer's Guide</div>
- <div class="author">by Gambardella, Matthew</div>
- <div>Genre: <span class="genre">Computer</span></div>
- <div class="price">Price: $44.95</div>
- <div>Published: 2000-10-01</div>
- <div>An in-depth look at creating applications with XML.</div>
- </div>
- <div class="book">
- <div class="title">Midnight Rain</div>
- <div class="author">by Ralls, Kim</div>
- <div>Genre: <span class="genre">Fantasy</span></div>
- <div class="price">Price: $5.95</div>
- <div>Published: 2000-12-16</div>
- <div>A former architect battles corporate zombies.</div>
- </div>
- <div class="book">
- <div class="title">Maeve Ascendant</div>
- <div class="author">by Corets, Eva</div>
- <div>Genre: <span class="genre">Fantasy</span></div>
- <div class="price">Price: $5.95</div>
- <div>Published: 2000-11-17</div>
- <div>After the collapse of a nanotechnology society, the young survivors band together.</div>
- </div>
- </body>
- </html>
复制代码
案例2:XML到XML的转换
在这个例子中,我们将把一个XML文档转换为另一个具有不同结构的XML文档。假设我们有一个包含订单信息的XML文档,我们想要将其转换为发票格式的XML文档。
源XML文档(order.xml):
- <?xml version="1.0" encoding="UTF-8"?>
- <order id="ORD12345">
- <customer>
- <name>John Doe</name>
- <address>123 Main St, Anytown, USA</address>
- <email>john.doe@example.com</email>
- </customer>
- <items>
- <item id="IT001">
- <name>Laptop</name>
- <quantity>1</quantity>
- <price>999.99</price>
- </item>
- <item id="IT002">
- <name>Mouse</name>
- <quantity>2</quantity>
- <price>19.99</price>
- </item>
- <item id="IT003">
- <name>Keyboard</name>
- <quantity>1</quantity>
- <price>49.99</price>
- </item>
- </items>
- <order_date>2023-05-15</order_date>
- <shipping_method>Express</shipping_method>
- </order>
复制代码
XSLT样式表(order-to-invoice.xsl):
- <?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" encoding="UTF-8"/>
-
- <xsl:template match="/">
- <invoice>
- <xsl:attribute name="invoice_id">
- <xsl:value-of select="concat('INV', substring-after(order/@id, 'ORD'))"/>
- </xsl:attribute>
- <xsl:attribute name="order_id">
- <xsl:value-of select="order/@id"/>
- </xsl:attribute>
- <xsl:attribute name="invoice_date">
- <xsl:value-of select="current-date()"/>
- </xsl:attribute>
-
- <bill_to>
- <name><xsl:value-of select="order/customer/name"/></name>
- <address><xsl:value-of select="order/customer/address"/></address>
- <email><xsl:value-of select="order/customer/email"/></email>
- </bill_to>
-
- <invoice_items>
- <xsl:apply-templates select="order/items/item"/>
- </invoice_items>
-
- <summary>
- <subtotal><xsl:value-of select="sum(order/items/item/(price * quantity))"/></subtotal>
- <tax><xsl:value-of select="sum(order/items/item/(price * quantity)) * 0.08"/></tax>
- <shipping>
- <xsl:choose>
- <xsl:when test="order/shipping_method = 'Express'">25.00</xsl:when>
- <xsl:otherwise>10.00</xsl:otherwise>
- </xsl:choose>
- </shipping>
- <total>
- <xsl:value-of select="sum(order/items/item/(price * quantity)) * 1.08 +
- (order/shipping_method = 'Express' * 25 + (order/shipping_method != 'Express') * 10)"/>
- </total>
- </summary>
- </invoice>
- </xsl:template>
-
- <xsl:template match="item">
- <item>
- <xsl:attribute name="id">
- <xsl:value-of select="@id"/>
- </xsl:attribute>
- <name><xsl:value-of select="name"/></name>
- <quantity><xsl:value-of select="quantity"/></quantity>
- <unit_price><xsl:value-of select="price"/></unit_price>
- <total_price><xsl:value-of select="price * quantity"/></total_price>
- </item>
- </xsl:template>
- </xsl:stylesheet>
复制代码
转换后的XML输出(invoice.xml):
- <?xml version="1.0" encoding="UTF-8"?>
- <invoice invoice_id="INV12345" order_id="ORD12345" invoice_date="2023-05-20">
- <bill_to>
- <name>John Doe</name>
- <address>123 Main St, Anytown, USA</address>
- <email>john.doe@example.com</email>
- </bill_to>
- <invoice_items>
- <item id="IT001">
- <name>Laptop</name>
- <quantity>1</quantity>
- <unit_price>999.99</unit_price>
- <total_price>999.99</total_price>
- </item>
- <item id="IT002">
- <name>Mouse</name>
- <quantity>2</quantity>
- <unit_price>19.99</unit_price>
- <total_price>39.98</total_price>
- </item>
- <item id="IT003">
- <name>Keyboard</name>
- <quantity>1</quantity>
- <unit_price>49.99</unit_price>
- <total_price>49.99</total_price>
- </item>
- </invoice_items>
- <summary>
- <subtotal>1089.96</subtotal>
- <tax>87.1968</tax>
- <shipping>25.00</shipping>
- <total>1202.1568</total>
- </summary>
- </invoice>
复制代码
案例3:XML到CSV的转换
在这个例子中,我们将把一个包含员工信息的XML文档转换为CSV格式,以便在电子表格软件中处理。
源XML文档(employees.xml):
- <?xml version="1.0" encoding="UTF-8"?>
- <employees>
- <employee id="EMP001">
- <name>John Smith</name>
- <department>IT</department>
- <position>Developer</position>
- <salary>75000</salary>
- <hire_date>2018-05-15</hire_date>
- </employee>
- <employee id="EMP002">
- <name>Jane Doe</name>
- <department>HR</department>
- <position>Manager</position>
- <salary>85000</salary>
- <hire_date>2016-08-22</hire_date>
- </employee>
- <employee id="EMP003">
- <name>Bob Johnson</name>
- <department>Finance</department>
- <position>Analyst</position>
- <salary>65000</salary>
- <hire_date>2020-01-10</hire_date>
- </employee>
- </employees>
复制代码
XSLT样式表(employees-to-csv.xsl):
- <?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>ID,Name,Department,Position,Salary,Hire Date </xsl:text>
- <xsl:apply-templates select="employees/employee"/>
- </xsl:template>
-
- <xsl:template match="employee">
- <xsl:value-of select="@id"/>
- <xsl:text>,</xsl:text>
- <xsl:value-of select="name"/>
- <xsl:text>,</xsl:text>
- <xsl:value-of select="department"/>
- <xsl:text>,</xsl:text>
- <xsl:value-of select="position"/>
- <xsl:text>,</xsl:text>
- <xsl:value-of select="salary"/>
- <xsl:text>,</xsl:text>
- <xsl:value-of select="hire_date"/>
- <xsl:text> </xsl:text>
- </xsl:template>
- </xsl:stylesheet>
复制代码
转换后的CSV输出(employees.csv):
- ID,Name,Department,Position,Salary,Hire Date
- EMP001,John Smith,IT,Developer,75000,2018-05-15
- EMP002,Jane Doe,HR,Manager,85000,2016-08-22
- EMP003,Bob Johnson,Finance,Analyst,65000,2020-01-10
复制代码
案例4:复杂XML结构的处理
在这个例子中,我们将处理一个更复杂的XML结构,包含嵌套元素和多个命名空间。假设我们有一个包含产品目录的XML文档,我们想要生成一个按类别分组的HTML页面。
源XML文档(products.xml):
- <?xml version="1.0" encoding="UTF-8"?>
- <catalog xmlns="http://example.com/catalog" xmlns:media="http://example.com/media">
- <category id="CAT001" name="Electronics">
- <product id="PRD001">
- <name>Smartphone</name>
- <description>A high-end smartphone with advanced features</description>
- <price currency="USD">699.99</price>
- <specifications>
- <spec name="Screen Size">6.5 inches</spec>
- <spec name="Storage">128 GB</spec>
- <spec name="RAM">6 GB</spec>
- </specifications>
- <media:images>
- <media:image url="images/smartphone_front.jpg" type="front"/>
- <media:image url="images/smartphone_back.jpg" type="back"/>
- </media:images>
- </product>
- <product id="PRD002">
- <name>Laptop</name>
- <description>Powerful laptop for work and gaming</description>
- <price currency="USD">1299.99</price>
- <specifications>
- <spec name="Screen Size">15.6 inches</spec>
- <spec name="Storage">512 GB SSD</spec>
- <spec name="RAM">16 GB</spec>
- </specifications>
- <media:images>
- <media:image url="images/laptop_open.jpg" type="open"/>
- <media:image url="images/laptop_closed.jpg" type="closed"/>
- </media:images>
- </product>
- </category>
- <category id="CAT002" name="Home Appliances">
- <product id="PRD003">
- <name>Refrigerator</name>
- <description>Energy-efficient refrigerator with ice maker</description>
- <price currency="USD">899.99</price>
- <specifications>
- <spec name="Capacity">25 cubic feet</spec>
- <spec name="Energy Rating">A++</spec>
- <spec name="Features">Ice maker, Water dispenser</spec>
- </specifications>
- <media:images>
- <media:image url="images/refrigerator_exterior.jpg" type="exterior"/>
- <media:image url="images/refrigerator_interior.jpg" type="interior"/>
- </media:images>
- </product>
- </category>
- </catalog>
复制代码
XSLT样式表(products-to-html.xsl):
- <?xml version="1.0" encoding="UTF-8"?>
- <xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:cat="http://example.com/catalog"
- xmlns:media="http://example.com/media"
- exclude-result-prefixes="cat media">
-
- <xsl:output method="html" indent="yes" encoding="UTF-8"/>
-
- <xsl:template match="/">
- <html>
- <head>
- <title>Product Catalog</title>
- <style>
- body { font-family: Arial, sans-serif; margin: 20px; }
- .category { margin-bottom: 30px; }
- .category-header { background-color: #f0f0f0; padding: 10px; font-size: 1.2em; font-weight: bold; }
- .product { margin: 15px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
- .product-name { font-weight: bold; font-size: 1.1em; color: #333; }
- .product-price { color: #009900; font-weight: bold; }
- .specifications { margin: 10px 0; }
- .spec { margin: 5px 0; }
- .images { margin: 10px 0; }
- .image { display: inline-block; margin-right: 10px; }
- </style>
- </head>
- <body>
- <h1>Product Catalog</h1>
- <xsl:apply-templates select="cat:catalog/cat:category"/>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="cat:category">
- <div class="category">
- <div class="category-header">
- <xsl:value-of select="@name"/>
- </div>
- <xsl:apply-templates select="cat:product"/>
- </div>
- </xsl:template>
-
- <xsl:template match="cat:product">
- <div class="product">
- <div class="product-name">
- <xsl:value-of select="cat:name"/>
- </div>
- <div>
- <xsl:value-of select="cat:description"/>
- </div>
- <div class="product-price">
- Price: <xsl:value-of select="cat:price"/> <xsl:value-of select="cat:price/@currency"/>
- </div>
- <div class="specifications">
- <h3>Specifications:</h3>
- <xsl:for-each select="cat:specifications/cat:spec">
- <div class="spec">
- <strong><xsl:value-of select="@name"/>:</strong> <xsl:value-of select="."/>
- </div>
- </xsl:for-each>
- </div>
- <div class="images">
- <h3>Images:</h3>
- <xsl:for-each select="media:images/media:image">
- <div class="image">
- <img src="{@url}" alt="{@type} view" width="150"/>
- <div><xsl:value-of select="@type"/></div>
- </div>
- </xsl:for-each>
- </div>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
转换后的HTML输出:
- <html>
- <head>
- <title>Product Catalog</title>
- <style>
- body { font-family: Arial, sans-serif; margin: 20px; }
- .category { margin-bottom: 30px; }
- .category-header { background-color: #f0f0f0; padding: 10px; font-size: 1.2em; font-weight: bold; }
- .product { margin: 15px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
- .product-name { font-weight: bold; font-size: 1.1em; color: #333; }
- .product-price { color: #009900; font-weight: bold; }
- .specifications { margin: 10px 0; }
- .spec { margin: 5px 0; }
- .images { margin: 10px 0; }
- .image { display: inline-block; margin-right: 10px; }
- </style>
- </head>
- <body>
- <h1>Product Catalog</h1>
- <div class="category">
- <div class="category-header">Electronics</div>
- <div class="product">
- <div class="product-name">Smartphone</div>
- <div>A high-end smartphone with advanced features</div>
- <div class="product-price">Price: 699.99 USD</div>
- <div class="specifications">
- <h3>Specifications:</h3>
- <div class="spec"><strong>Screen Size:</strong> 6.5 inches</div>
- <div class="spec"><strong>Storage:</strong> 128 GB</div>
- <div class="spec"><strong>RAM:</strong> 6 GB</div>
- </div>
- <div class="images">
- <h3>Images:</h3>
- <div class="image">
- <img src="images/smartphone_front.jpg" alt="front view" width="150">
- <div>front</div>
- </div>
- <div class="image">
- <img src="images/smartphone_back.jpg" alt="back view" width="150">
- <div>back</div>
- </div>
- </div>
- </div>
- <div class="product">
- <div class="product-name">Laptop</div>
- <div>Powerful laptop for work and gaming</div>
- <div class="product-price">Price: 1299.99 USD</div>
- <div class="specifications">
- <h3>Specifications:</h3>
- <div class="spec"><strong>Screen Size:</strong> 15.6 inches</div>
- <div class="spec"><strong>Storage:</strong> 512 GB SSD</div>
- <div class="spec"><strong>RAM:</strong> 16 GB</div>
- </div>
- <div class="images">
- <h3>Images:</h3>
- <div class="image">
- <img src="images/laptop_open.jpg" alt="open view" width="150">
- <div>open</div>
- </div>
- <div class="image">
- <img src="images/laptop_closed.jpg" alt="closed view" width="150">
- <div>closed</div>
- </div>
- </div>
- </div>
- </div>
- <div class="category">
- <div class="category-header">Home Appliances</div>
- <div class="product">
- <div class="product-name">Refrigerator</div>
- <div>Energy-efficient refrigerator with ice maker</div>
- <div class="product-price">Price: 899.99 USD</div>
- <div class="specifications">
- <h3>Specifications:</h3>
- <div class="spec"><strong>Capacity:</strong> 25 cubic feet</div>
- <div class="spec"><strong>Energy Rating:</strong> A++</div>
- <div class="spec"><strong>Features:</strong> Ice maker, Water dispenser</div>
- </div>
- <div class="images">
- <h3>Images:</h3>
- <div class="image">
- <img src="images/refrigerator_exterior.jpg" alt="exterior view" width="150">
- <div>exterior</div>
- </div>
- <div class="image">
- <img src="images/refrigerator_interior.jpg" alt="interior view" width="150">
- <div>interior</div>
- </div>
- </div>
- </div>
- </div>
- </body>
- </html>
复制代码
XSLT最佳实践和性能优化
模板设计原则
1. 保持模板简单和专注:每个模板应该专注于处理一种特定类型的节点,避免过于复杂的逻辑。
2. 使用模板匹配而不是条件语句:尽可能使用模板匹配(xsl:template的match属性)而不是条件语句(xsl:if或xsl:choose),这样可以更好地利用XSLT的处理模型。
3. 避免过度使用xsl:for-each:虽然xsl:for-each在某些情况下很有用,但过度使用会导致代码难以维护。考虑使用模板匹配和xsl:apply-templates代替。
保持模板简单和专注:每个模板应该专注于处理一种特定类型的节点,避免过于复杂的逻辑。
使用模板匹配而不是条件语句:尽可能使用模板匹配(xsl:template的match属性)而不是条件语句(xsl:if或xsl:choose),这样可以更好地利用XSLT的处理模型。
避免过度使用xsl:for-each:虽然xsl:for-each在某些情况下很有用,但过度使用会导致代码难以维护。考虑使用模板匹配和xsl:apply-templates代替。
性能优化技巧
1. 使用键(key)提高查找效率:对于频繁的节点查找,使用xsl:key定义键可以显著提高性能。
示例:
- <xsl:key name="product-by-id" match="product" use="@id"/>
- <!-- 使用键查找产品 -->
- <xsl:value-of select="key('product-by-id', 'PRD001')/name"/>
复制代码
1. 避免在循环中使用XPath表达式:在xsl:for-each循环中,避免在每次迭代中重复计算相同的XPath表达式。考虑使用变量存储结果。
示例:
- <!-- 不推荐 -->
- <xsl:for-each select="products/product">
- <xsl:if test="price > catalog/min_price">
- <!-- 处理产品 -->
- </xsl:if>
- </xsl:for-each>
- <!-- 推荐 -->
- <xsl:variable name="min-price" select="catalog/min_price"/>
- <xsl:for-each select="products/product">
- <xsl:if test="price > $min-price">
- <!-- 处理产品 -->
- </xsl:if>
- </xsl:for-each>
复制代码
1. 使用适当的XPath表达式:避免使用过于宽泛的XPath表达式,如//,它们会导致处理器搜索整个文档。
示例:
- <!-- 不推荐 -->
- <xsl:value-of select="//product[@id='PRD001']/name"/>
- <!-- 推荐 -->
- <xsl:value-of select="catalog/category/product[@id='PRD001']/name"/>
复制代码
1. 减少输出的大小:如果输出文档很大,考虑使用xsl:output的indent="no"属性来减少空白字符。
2. 使用XSLT 2.0或更高版本:如果可能,使用XSLT 2.0或3.0,它们提供了更多的功能和更好的性能。
减少输出的大小:如果输出文档很大,考虑使用xsl:output的indent="no"属性来减少空白字符。
使用XSLT 2.0或更高版本:如果可能,使用XSLT 2.0或3.0,它们提供了更多的功能和更好的性能。
可维护性建议
1. 使用注释和文档:为复杂的XSLT代码添加注释,解释其目的和工作方式。
2. 模块化样式表:使用xsl:import和xsl:include将大型XSLT样式表分解为更小、更易管理的模块。
使用注释和文档:为复杂的XSLT代码添加注释,解释其目的和工作方式。
模块化样式表:使用xsl:import和xsl:include将大型XSLT样式表分解为更小、更易管理的模块。
示例:
- <!-- 主样式表 -->
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:import href="common-templates.xsl"/>
- <xsl:import href="product-templates.xsl"/>
- <xsl:import href="formatting-templates.xsl"/>
-
- <!-- 主样式表内容 -->
- </xsl:stylesheet>
复制代码
1. 使用命名约定:为变量、参数和模板使用一致的命名约定,以提高代码的可读性。
2. 避免硬编码值:将可能变化的值(如文本标签、格式选项等)提取为变量或参数,以便于修改。
使用命名约定:为变量、参数和模板使用一致的命名约定,以提高代码的可读性。
避免硬编码值:将可能变化的值(如文本标签、格式选项等)提取为变量或参数,以便于修改。
调试和测试
1. 使用XSLT调试器:许多XSLT处理器和IDE提供了调试工具,可以帮助你逐步执行XSLT代码并检查变量值。
2. 输出中间结果:在开发过程中,使用xsl:message或临时输出元素来检查中间结果。
使用XSLT调试器:许多XSLT处理器和IDE提供了调试工具,可以帮助你逐步执行XSLT代码并检查变量值。
输出中间结果:在开发过程中,使用xsl:message或临时输出元素来检查中间结果。
示例:
- <xsl:template match="product">
- <xsl:message>Processing product: <xsl:value-of select="@id"/></xsl:message>
- <!-- 模板内容 -->
- </xsl:template>
复制代码
1. 测试各种输入场景:确保你的XSLT代码能够处理各种输入情况,包括边界情况和错误情况。
2. 使用XSLT测试框架:考虑使用XSLT测试框架(如XSpec)来自动化测试过程。
测试各种输入场景:确保你的XSLT代码能够处理各种输入情况,包括边界情况和错误情况。
使用XSLT测试框架:考虑使用XSLT测试框架(如XSpec)来自动化测试过程。
常见问题和解决方案
问题1:处理命名空间
问题:当源XML文档使用命名空间时,XPath表达式可能无法正确匹配节点。
解决方案:在XSLT样式表中声明相同的命名空间,并在XPath表达式中使用前缀。
示例:
- <!-- 源XML -->
- <catalog xmlns="http://example.com/catalog">
- <product id="PRD001">
- <name>Smartphone</name>
- </product>
- </catalog>
- <!-- XSLT样式表 -->
- <xsl:stylesheet version="1.0"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:cat="http://example.com/catalog"
- exclude-result-prefixes="cat">
-
- <xsl:template match="/">
- <xsl:value-of select="cat:catalog/cat:product/cat:name"/>
- </xsl:template>
- </xsl:stylesheet>
复制代码
问题2:处理特殊字符和CDATA
问题:源XML中的特殊字符(如<, >, &)或CDATA部分可能无法正确处理或输出。
解决方案:使用xsl:text或xsl:output的相应属性来控制特殊字符的处理。
示例:
- <!-- 输出包含特殊字符的文本 -->
- <xsl:text>This is a <test> with special characters.</xsl:text>
- <!-- 输出CDATA部分 -->
- <xsl:text disable-output-escaping="yes"><![CDATA[This is CDATA content]]></xsl:text>
复制代码
问题3:处理日期和时间
问题:XSLT 1.0对日期和时间的处理能力有限,难以进行日期计算和格式化。
解决方案:在XSLT 1.0中使用扩展函数或字符串操作,或者升级到XSLT 2.0/3.0,它们提供了丰富的日期和时间函数。
示例(XSLT 2.0):
- <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:template match="/">
- <xsl:variable name="today" select="current-date()"/>
- <xsl:variable name="order-date" select="xs:date('2023-05-15')"/>
-
- <p>Today: <xsl:value-of select="format-date($today, '[D01] [MNn] [Y0001]')"/></p>
- <p>Order date: <xsl:value-of select="format-date($order-date, '[D01] [MNn] [Y0001]')"/></p>
- <p>Days since order: <xsl:value-of select="days-from-duration($today - $order-date)"/></p>
- </xsl:template>
- </xsl:stylesheet>
复制代码
问题4:处理大型XML文档
问题:当处理大型XML文档时,可能会遇到内存不足或性能问题。
解决方案:
1. 使用流式处理(XSLT 3.0的流式转换)
2. 优化XPath表达式,避免使用//
3. 使用键(key)提高查找效率
4. 考虑将大型文档分解为较小的部分进行处理
示例(XSLT 3.0流式处理):
- <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:mode streamable="yes"/>
-
- <xsl:template match="/">
- <html>
- <body>
- <h1>Large Document Processing</h1>
- <xsl:apply-templates select="large-document/record"/>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="record">
- <div>
- <xsl:value-of select="id"/>: <xsl:value-of select="name"/>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
问题5:处理多语言和国际化
问题:需要根据不同的语言环境生成不同语言的输出,或者处理多语言内容。
解决方案:使用参数和变量来控制语言选择,或者使用专门的国际化技术。
示例:
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:param name="lang" select="'en'"/>
-
- <xsl:variable name="texts">
- <text lang="en" name="title">Product Catalog</text>
- <text lang="en" name="price">Price</text>
- <text lang="fr" name="title">Catalogue de Produits</text>
- <text lang="fr" name="price">Prix</text>
- </xsl:variable>
-
- <xsl:template name="get-text">
- <xsl:param name="name"/>
- <xsl:value-of select="$texts/text[@lang=$lang and @name=$name]"/>
- </xsl:template>
-
- <xsl:template match="/">
- <html>
- <body>
- <h1><xsl:call-template name="get-text"><xsl:with-param name="name" select="'title'"/></xsl:call-template></h1>
- <xsl:apply-templates select="catalog/product"/>
- </body>
- </html>
- </xsl:template>
-
- <xsl:template match="product">
- <div>
- <h2><xsl:value-of select="name"/></h2>
- <p>
- <xsl:call-template name="get-text"><xsl:with-param name="name" select="'price'"/></xsl:call-template>:
- <xsl:value-of select="price"/>
- </p>
- </div>
- </xsl:template>
- </xsl:stylesheet>
复制代码
总结与展望
XSLT是一种强大而灵活的语言,用于转换XML文档。通过本文的介绍,我们了解了XSLT的基础语法、核心元素、高级功能以及实际应用案例。无论是将XML转换为HTML用于网页显示,还是转换为其他XML格式以满足不同系统的需求,XSLT都能提供有效的解决方案。
随着XML在数据交换和文档处理领域的广泛应用,掌握XSLT技能变得越来越重要。通过遵循最佳实践和性能优化技巧,我们可以开发出高效、可维护的XSLT样式表,解决各种复杂的数据转换问题。
展望未来,XSLT仍在不断发展。XSLT 3.0引入了许多新特性,如流式处理、更高阶的函数和更好的JSON支持,使其能够适应现代数据处理的需求。随着这些新特性的普及,XSLT将继续在数据转换和处理领域发挥重要作用。
无论你是初学者还是有经验的开发者,希望本文能够帮助你更好地理解和应用XSLT,轻松实现XML数据的格式化与转换。通过不断学习和实践,你将能够掌握这一强大的技术,为你的项目带来更多的可能性和价值。
版权声明
1、转载或引用本网站内容(掌握XSLT技巧轻松实现XML数据格式化与转换从基础语法到实际应用全面解析XML文档样式表处理方法)须注明原网址及作者(威震华夏关云长),并标明本网站网址(https://pixtech.org/)。
2、对于不当转载或引用本网站内容而引起的民事纷争、行政处理或其他损失,本网站不承担责任。
3、对不遵守本声明或其他违法、恶意使用本网站内容者,本网站保留追究其法律责任的权利。
本文地址: https://pixtech.org/thread-36741-1-1.html
|
|