2010-05-19
七、转换XML
l 可扩展样式表语言(XSL),被定义成了一种表示样式表的语言。是管理怎样从格式A转换一个文档到格式B的规范语言。该语言组件用于管理转换结构中的处理和身份验证
n XSL是一种用来转换XML文档的语言。
n XSL是一个用来指定XML文档格式的词汇库。
l XSL和树形描述:这个用XSL定义的规则本身已被树形结构所约束,涉及到了XML文档层次结构的简单过程。最大优点是它允许XML文档中的相关集合元素保持相同操作
l 格式化对象:几乎所有的XSL说明都与定义格式化对象(formatting object)有关。一个属性和词汇的大集合组成了格式化对象能够使用的特征集合。这也包括了能够被对象可视化区域的类型,以及线条、字体、图形和其他可视化对象的属性、内置的和成块的格式化对象,以及其他许多语法结构。
格式化对象经常大量被使用在把XML文本数据转化为二进制格式的场合,例如一个PDF文本,一个图像文件或者像WORD一样的文档格式。为了把XML数据转换成其他的文本格式,这些对象很少被明确使用。尽管对一个样式表逻辑的底层部分,格式化对象很少直接被调用,而结果的文本数据经常符合于已定义的标识语言,如HTML
l XSL转换(XSLT)是XML转换的第二个组件。XSLT是一种专门把文档从一种格式转换为另一种格式的语言。XSLT是一种能够从XML文档中产生HTML或者WML的工具。事实上,XSLT规范所概括的XSL样式表语法比XSL规范本身还更加明确。
同XSL一样,XSLT总是以良够的有效地XML。为能够描述所允许结构的XSL和XSLT专门定义了DTD。与XSL一样,XSLT也基于一个多层树形数据结构,在这个结构中最临近的元素是叶或父母节点的子节点。XSLT在原始XML文档中提供了一种样式匹配机制,这种机制对数据进行格式化。。并且这能够生成不含多余XML元素名的简单数据输出,或者插入数据到一个复杂的HTML表中,同时以高亮度和色彩演示给客户端。XSLT也能为许多常用操作提供语法机制,例如条件语句判断、树形结构文档的复制。复杂图形规范以及以一种完全的或相对的路径结构杂在输入的XML中附加元素的能力。
l XPath提供了一种在XML文档中能够引用多样元素和属性名及值的机制。为了完成元素的处理,XPath定义了与XML树形结构、XSL执行过程以及使用它的结构相关联的语法。XPath也定义了元素相对于文档中根节点的寻址位置。XPath为实际的规范匹配定义了语法。
n 一个XPath表达式能够处理无输入数据文件、单输入元素或属性文件以及多输入元素或属性文件以及多输入元素或属性属性。
n 通常将XPath表达式值的结果称为一个节点集(node set)。它也和层次或树形结构的观点联系了起来,通常会用叶或节点的术语来处理。节点集能够被转换、复制、忽略或执行其他的合法操作。
n XPath也定义了许多节点集函数,例如not()和count()。这些函数以节点集作为输入(以XPath表达式的形式),然后进一步处理结果。所有这些表达式和函数均是XPath说明或实现的一部分。XPath也常用来表示符合说明自身规则的任何表达式。
l XSL就是XML:任何一种XSL样式表所需完成的首要任务,是遵守XML规范。样式表必须是良构的,必须包含一个XML声明,必须声明它所用到的所有名字空间。使用前缀xsl的XSL名字空间,定义要转换的元素。这意味着样式表中凡是有助于转换进程的元素都会以那个名字空间作为前缀。XSL样式表的最基本任务,是在一个输入文档中确定一个特定元素或元素集合的位置,并对最终的XML运用一个规则或规则的集合。
l XSL模板。模板(template)的是运用在与特定XPath匹配的XML上的一系列规则的集合。使用XSL元素template来定义模板的概念。这个元素的定义应该和其属性一致。并且这个属性的值必须是与被处理的XML的零个或多个元素匹配的XPath表达式。
<xsl:template match=”[XPath expression]”>
<!-- Here are my rules and formatting -->
</xsl:template>
实际复杂性仅是如何创建一个与前面所选取的一个或多个XML元素匹配的XPath表达式。
XSL:apply-templates元素没有任何特定的属性要求,处理器将会在XSL样式表里德任何模板中匹配任何与当前元素相关的元素
另一种XSL结构,元素xsl:value-of,这种结构匹配Xpath表达式时包含了匹配输入的值
<xsl:template match="JavaXML:Book">
<html>
<head>
<title><xsl:value-of select="JavaXML:Title" /></title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
l 用XPath过滤:从XPath表达式返回的节点集合已经过了层次分析,XSLT解析器一次并不能处理XML文档中的所有元素。处理器以一种特定的层次安排来查询所有的元素,然后开始向下转移到每一个元素的树形结构汇总。在文档里就意味着XSLT处理器在根节点元素查看到的元素均是与根元素相差一个层次的元素
l XPath节点函数not()能够产生一个不与给定的XPath表达式相匹配的节点集合。
<xsl:apply-templates select=”*[not(myExpression)]” />
使用关键字self,让处理器明确self后的参考节点均是正在处理的当前节点的节点。使用双冒号把元素和关键字区分开,便于用单冒号来表示名字空间操作
<xsl:apply-templates select=”*[not(self::JavaXML:Title)]” />
l 循环:循环结构xsl:for-each适合在相同的元素类型里重复数据整理。通过特定select属性,xsl:for-each结构接收一个能够导致一个节点集合循环结束的XPath表达式。
<xsl:template match="JavaXML:Contents">
<center>
<h2>Table of Contents</h2>
</center>
<hr />
<ul>
<xsl:for-each select="JavaXML:Chapter">
<li><xsl:value-of select="JavaXML:Heading" /></li>
</xsl:for-each>
</ul>
</xsl:template>
l 选择处理的元素:XSL:if结构处理的结果为我们返回了既符合XPath表达式规范又满足用户约束的节点。当一个特定类型的所有数据都需要确定取值,并且只有数据的一个子集以某种特定的格式被显示或者被格式化时,使用这种结构将会是有帮助的。
<xsl:for-each select="JavaXML:Chapter">
<xsl:if test="@focus='Java'">
<li><xsl:value-of select="JavaXML:Heading" /></li>
</xsl:if>
</xsl:for-each>
使用test属性作为xsl:if的补充属性,如果取值为true,则元素xsl:if的内容将会被赋值。属性名前加@符号
xsl:choose xsl:when xsl:otherwise
<xsl:for-each select="JavaXML:Chapter">
<xsl:choose>
<xsl:when test="@focus='Java'">
<li><xsl:value-of select="JavaXML:Heading" />(Java focus)</li>
</xsl:when>
<xsl:otherwise>
<li><xsl:value-of select="JavaXML:Heading" />(XML focus)</li>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
l 需要输出的属性需要从一个输入到处理器的元素来构建,一个有效的方法是使用xsl:element和xsl:attribute结构为这些元素和属性设置数据取值。元素架构使用name属性来给定元素的名字,它的值是元素中的任何数据。
<xsl:element name=”myElement”>
<xsl:attribute name=”myAttribute”>
Java
</xsl”attribute>
is Greate!
</xsl:element>
上边的XSL将被赋值,结果输出如下:
<myElement myAttribute=”Java”>is Greate!</myElement>
如果允许任意实际的值都能在内部创建,用元素xsl:element和xsl:attribute将会产生更复杂的表达式。如下构建URL的工具:
<xsl:element name=”a”>
<xsl:attribute name=”href”>
<xsl:value-of select=”JavaXML:Url” />
</xsl:attribute>
<xsl:value-of select=”JavaXML:Name” />
</xsl:element>
l 如果模板不被指定为某一个元素时,将不会有输出,输入树将一直被跳过,直到遇到数据并且输出。如下载XML中加入HTML标记
<JavaXML:Copyright>
<center>
<table cellpadding="0" cellspacing="1" border="1" bgcolor="black">
<tr>
<td align="center">
<table bgcolor="white" border="2">
<tr>
<td>
<font size="-1">
Copyright O'Reilly and Associates,2000
</font>
</td>
</tr>
</table>
</td>
</tr>
</table>
</center>
</JavaXML:Copyright>
作为HTML标志进入处理器的会被处理成XML,所有的HTML标记在XML转换中被忽略。对于指定元素作为数据的问题的解决方案:使用结构xsl:copy-of。作用和结构xsl:value-of形式相同。xsl:copy-of代替输出返回节点集的值,经过从输入直接到输出的处理器扫描所有的节点集,所有在节点集里的内容并不发声转换。
<xsl:template match="JavaXML:Copyright">
<xsl:copy-of select="*" />
</xsl:template>
它通过了JavaXML:Copyright的内容(包括HTML代码)但未进行处理。不可认为这就给了你任何破坏XML规则的自由。
l 格式化对象:XML数据能够转换层几乎任何一种格式。使用格式化对象XSL就能产生XML区域;数据表示可以按二进制数据的方式进行处理。XML格式同时保持了原始和转换后文档的不同风格,继续使数据保持可移植性。
l 完整XSL样式表:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform
xmlns:JavaXML=http://www.oreilly.com/catalog/javaxml/
version="1.0"
>
<xsl:template match="JavaXML:Book">
<html>
<head>
<title><xsl:value-of select="JavaXML:Title" /></title>
</head>
<body>
<xsl:apply-templates select="*[not(self::JavaXML:Title)]" />
</body>
</html>
</xsl:template>
<xsl:template match="JavaXML:Contents">
<center>
<h2>Table of Contents</h2>
</center>
<hr />
<ul>
<xsl:for-each select="JavaXML:Chapter">
<xsl:choose>
<xsl:when test="@focus='Java'">
<li><xsl:value-of select="JavaXML:Heading" />(Java focus)</li>
</xsl:when>
<xsl:otherwise>
<li><xsl:value-of select="JavaXML:Heading" />(XML focus)</li>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="JavaXML:References">
<p>
<center><h3>Useful References</h3></center>
<ol>
<xsl:for-each select="JavaXML:Reference">
<li>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="JavaXML:Url" />
</xsl:attribute>
<xsl:value-of select="JavaXML:Name" />
</xsl:element>
</li>
</xsl:for-each>
</ol>
</p>
</xsl:template>
<xsl:template match="JavaXML:Copyright">
<xsl:copy-of select="*" />
</xsl:template>
</xsl:stylesheet>