用于转化的XML样式表语言

简介:

用于转换的XML样式表语言定义了用于寻址XML数据(XPath)以及指定这些数据转换的机制,以便将其转换成其他形式。JAXB包含两种XSLT实现、一个解释版本(Xalan)和一个编译版本(XSLTC),这些能让你将所要转换的预编译版本保存为translet,以便在稍后进行有效的运行时处理。

本章介绍了如何使用XalanXSLTC,如何将一个文档对象模型(DOM)作为XML文件写出来,如何从任意的数据文件生成一个DOM以将其转换成XML。最后还讲述了如何将XML数据转换成不同的形式,并剖析XPath寻址机制的神秘过程。

注意:本章中的例子可以在<JWSDP_HOME>/docs/tutorial/examples/jaxp/xslt/samples中找到。

XSLTXPath介绍

XML样式表语言有三个主要组成部分:

XSL-FO

 “流对象”标准。这是目前最大的组成部分,该标准给出了用于描述字体大小、页面布

局以及信息如何从一个页面“流”到另一个页面的机制。该组成部分不属于JAXP的范畴,也不是本教程的讨论范围。

XSLT

它就是转换语言,定义了从XML到一些其他格式的转换。例如,可以利用XSLT来产生HTML或者不同的XML结构。甚至可以利用它来生成纯文本或者将这些信息转换成其他的文档格式。(在从任意的数据结构生成XML中,一个很灵活的应用将用它来操作非XML的数据)

XPath

实际上,XSLT是一种能让你在遇到一个特定元素时,规定做什么事的语言。但是要想为XML数据结构的不同部分写出程序,还需要能够指定某一时刻正在谈论的部分。XPath就是这种规范语言。它是一个寻址机制,能让你指定到某个元素的路径,从而可以区分<article><title><person><title>。这样就能够为各种<title>元素描述不同种类的转换。

本节的其余部分描述了组成JAXP转换API的包,接着讨论了用来选择XalanXSLTC转换引擎的工厂配置参数。

JAXP转换包

组成JAXP转换API的包的描述如下:

javax.xml.transform

这个包定义了用来获得Transformer对象的工厂类。接着可以利用输入(源)和输出(结果)对象来配置转换器,并调用它的transform()方法来进行转换。源和结果对象是用来自其他三个包的对象创建的。

(得到的是Xalan解释转换器还是XSLTC编译转换器,取决于工厂配置设置,这马上就会讲到)。

javax.xml.transform.dom

定义了DOMSourceDOMResult类,这些类允许将DOM用作某个转换的输入或输出。

javax.xml.transform.sax

定义了SAXSource SAXResult类,这些类允许将SAX事件生成器用作某个转换的输入,或者将SAX事件用作SAX事件处理器的输出。

javax.xml.transform.stream

定义了StreamSourceStreamResult类,这些类允许将一个I/O流用作某个转换的输入或输出。

选择转换引擎

本节提供的信息有助于在解释转换器(Xalan)和编译转换器(XSLTC)之间作出选择。

性能考虑

对于一个单次(single-pass)转换,解释转换器(Xalan)的速度比编译转换器(XSLTC)稍快,因为它不在作为translet运行的小Java类中生成和保存字节码。

但在需要多次用到一个转换时,使用XSLTC转换引擎就好的多,这是因为在这种情况下它更符合内存需求和性能指标。

XSLTC translet很小,因为它只实现样式表实际上进行的那些转换。并且它速度也很快,一方面是由于小,另一方面是由于解释样式表所需的词汇处理已经进行过了。最后,由于translet的体积小,所以加载速度更快,且占用的系统资源更少。

例如,一个需要运行很长一段时间的servlet会从XSLTC中受益。同样,使用XSLTC时,从命令行运行的转换速度也更快。关于这个过程的更多信息,请参见从命令行转换

除了能缓存tranletXSLTC还提供了很多有助于最大化性能的其他选项:

  • 内联控制

默认情况下,XSLTC会“内联”转换码,这意味着负责转换元素的代码中包含该元素所有子元素的转换码。

对于小型和中等的样式表,该实现生成的代码可能是最快的。但复杂样式表生成的translet则可能会大的出奇。

为了解决这个问题,XSLTC允许禁用内联功能。为此,在从命令行编译XSLTC translet时需要使用-n选项。当利用JAXP工厂类生成XSLTC转换器时,需要使用工厂的setAttribute()方法来设置"disable-inlining"特性,代码如下:

TransformerFactory tf = new TransformerFactory();
tf.setAttribute("disable-inlining", Boolean.TRUE);

  • 文档模型缓存

XSLTCXML数据上运行时,创建了自己的内部文档对象模型(这和你见过的W3C DOM类似,只不过简单了点)。由于该文档模型的构建很费时间,XSLTC就提供了一种缓存该模型的方法,以帮助加速子元素的转换。

这个特性在提供XML文档的servlet中迟早会有用。如果在访问Web上的这些文档时,它们被转换成了HTML,那么缓存这些文档的内存中表示(in-memory representation)可能对性能产生巨大的影响。下面是一些可以使用的示例代码:

final SAXParser parser = factory.newSAXParser();
final XMLReader reader = parser.getXMLReader();

XSLTCSource source = new XSLTCSource();
source.build(reader, xmlfile);

于是source对象不需要重新读取文件就可以在多个转换中重复使用。

  • 缓存编译过的样式表

XSLTC还允许保存编译过的样式表,这样就能用它们来更快地创建多个Transformer对象。例如,这种能力能加快多线程servlet的启动速度。如果该servlet为输入请求生成了一百个线程,它可以一次性地编译样式表,然后利用这个编译过的版本为每个线程生成转换器。

预编译过的样式表存放在Templates对象中。直接创建Transformer对象(不使用Templates对象)时使用的代码如下:

TransformerFactory factory =
    TransformerFactory.newInstance();
Transformer xformer = factory.newTransformer(myStyleSheet);
xformer.transform(myXmlInput,
    new StreamResult(System.out));

但也可以创建一个可以保存和重新利用的中间Templates对象,代码如下:

TransformerFactory factory =
    TransformerFactory.newInstance();
Templates templates = factory.newTemplates(myStyleSheet);
Transformer xformer = templates.newTransformer();
xformer.transform(myXmlInput, 
    new StreamResult(System.out));

注意:为获得XSLT的最大性能,在设计样式表时有很多事情是需要做的,同时有很多事情是需要避免的。关于这个话题的更多信息,见http://xml.apache.org/xalan-j/xsltc/xsltc_performance.html

功能考虑

虽然从性能上考虑XSLTC对于很多应用来说是一个更好的选择,但在功能上Xalan却有自己的优势。支持标准的查询语言SQL就是其中之一。

作出选择

得到的是Xalan转换引擎还是XSLTC转换引擎,取决于工厂配置设置。默认情况下,JAXP工厂创建的是Xalan转换器。为了获得XSLTC转换器,最好的方法是设置如下的TransformationFactory系统属性。

javax.xml.transform.TransformerFactory=
    org.apache.xalan.xsltc.trax.TransformerFactoryImpl 

但有时候设置系统属性是不可能的,因为该应用是一个servlet,并且更改系统属性会影响运行在同一个容器中的其他servlet。这种情况下,可以直接实例化XSLTC转换引擎,命令如下:

new org.apache.xalan.xsltc.trax.TransformerFactoryImpl(..) 

还可以将工厂值传递给应用,然后使用ClassLoader在运行时创建它的一个实例。

注意:要想明确地指定Xalan转换器,需要使用值org.apache.xalan.processor.TransformerFactoryImpl,而不是org.apache.xalan.xsltc.trax.TransformerFactoryImpl

有一个“智能转换器”,它在生成Transformer对象时使用Xalan转换引擎,而在生成中间Templates对象时使用XSLTC转换引擎。为了获得该智能转换器的实例,需要使用值org.apache.xalan.xsltc.trax.SmartTransformerImpl,以设置转换器工厂的系统属性,或者直接利用那个类来实例化解析器。

XPath的工作原理

XPath规范是各种规范的基础,这些规范包括像XPointer这样的XSLT和链接/寻址规范。所以理解XPath是使用很多高级XML用法的基础条件。本节完整地介绍了XSLT上下文中的XPATH,供后面需要时参考。

注意:在本教程中,只有看了本节后面的使用XSLT转换XML数据才可能真正地利用XPath。但是如果你愿意,可以跳过本节直接跳到下一节作为XML文件写出DOM。(在那一节的结尾会提示你回到这里,切记!)

XPATH表达式

通常,XPath表达式规定了选中一组XML节点的模式(pattern)。XSLT模板在应用转换时使用这些模式(而XPointer增加了用于定义点(point)或范围(range)的机制,因此XPath表达式可用于寻址)。

XPath表达式中的节点不仅仅指的是元素。它们也可以是文本、属性以及其他东西。实际上,XPath规范定义了一个抽象的文档模型,该模型定义了七种不同的节点,它们是:

·   

·   元素

·   文本

·   属性

·   注释

·   处理指令

·   命名空间

注意:XML数据的根元素是通过元素节点形成的。XPath根节点包含了文档的根元素,以及与该文档有关的其他信息。

XSLT/XPath数据模型

DOM一样,XSLT/XPath数据模型也由一个包含各种节点的树组成。在任意给定的元素节点下,都有文本节点、属性节点、元素节点、注释节点和处理指令节点。

在该抽象模型中,没有语法上的区别,所有数据都是规范化的。比如在文本节点中,文本是否定义在CDATA部分中或者它是否包含实体引用,都无所谓。文本节点由规范化的数据组成,因为它在所有的解析都完成之后才生成。所以,不管该文本包含在像&lt;这样的实体引用中还是在CDATA部分中,它都包含一个<字符。(同样,不管该文本利用&amp;传送还是在CDATA部分中传送,它都包含一个&字符。)

该教程的这一节主要讨论元素节点和文本节点。

模板和上下文

XSLT模板是一组适用于XPATH表达式选定的节点的格式化指令。在样式表中,XSLT模板如下所示:

<xsl:template match="//LIST">
    ...
</xsl:template> 

表达式//LIST从输入流中选中一组LIST节点。该模板中的附加指令会告诉系统如何处理。

被这样一个表达式选中的一组节点定义了上下文,并且模板中其他表达式的值就是在这个上下文中计算出来的。在确定上下文中包含了多少个节点时,它被作为一个整体考虑。

上下文也可以看成是该组中的单个成员,因为每个成员是逐个被处理的。例如,在LIST处理模板中,表达式@type指当前LIST节点的type属性。(同样,表达式@*指当前LIST元素的所有属性)。

基本的XPath寻址

XML文档是一个树型结构(分层)的节点集合。和分层目录结构一样,该树型结构规定了一个指向某一节点的路径。(此规范因此而得名:XPath。)实际上,很多目录路径的符号在传输过程中保持原样。

·   正斜杠/用作路径的分隔符。

·   到文档根部的绝对路径以/开始。

·   到给定位置的相对路径以其他符号开始。

·   双句点..表示当前节点的父节点。

·   单句点.表示当前节点。

例如,在XHTML文档(和HTML类似的一种XML文档,只不过根据XML的规则它的形式是well-formed)中,路径/h1/h2/表示h1下面的h2元素。(回想一下,在XML中元素名区分大小写,所以这种类型的规范在XHTML中要比在纯HTML中有效,因为HTML不区分大小写。)

在像 XSLT这样的模式匹配规范中,规范/h1/h2选中所有位于h1元素之下的h2元素。要想选中某一特定的h2元素,需要利用方括号[]进行索引(就像数组中那样)。例如,路径/h1[4]/h2[5]选中了第四个h1元素下的第五个h2元素。

注意:在XHTML中,所有的元素名都是小写的。这是XML文档中常见的命名约定。本教程中的名称用大写只是为了读起来方便。所以,在该XSLT教程中其他部分中,所有的XML元素名都用大写表示。(属性名仍用小写表示。)

XPath表达式中规定的名称指的是一个元素。例如,/h1/h2中的h1表示h1元素。要想引用某个属性,需要在该属性名的前面加上一个@符号。例如,@type表示元素的type属性。如果已经有了一个具有LIST元素的XML文档,表达式LIST/@type将选中LIST元素的type属性。

注意:由于该表达式不是以/开始的,所以这个引用指定了一个与当前上下文有关的list节点——所谓当前上下文是指文档中的当前位置。

基本的XPath表达式

所有的XPath表达式都利用了XPath定义的通配符、运算符和函数。关于这些内容你很快就会学到。这里,我们先看一对最常用的XPath表达式。只是简单的介绍一下,不作深入讨论。

表达式@type="unordered"指定了一个名为type的属性,它的值为"unordered"。并且我们已经知道像LIST/@type这样的表达式指定了LIST元素的type属性。

将这两个符号结合起来将看到一些很有趣的事!在XPath中,与索引有关的方括号([])的含义通常被延伸,它还能指定选择条件(selection criteria)。所以表达式LIST[@type="unordered"]选中所有type值为"unordered"LIST元素。

元素的表达式也差不多,其中每个元素都有一个相关的字符串值(string-value)。(稍后你将会看到如何为一个复杂元素确定字符串值。但现在我们仍然讲只有一个文本字符串的简单元素。)。

假定你在公司创建了一个由PROJECT元素和ACTIVITY元素组成的 XML结构,这两种元素有一个文本字符串,其中字符串包括项目名、用来列出相关人员的多个PERSON元素,以及一个可选的记录项目状态的STATUS元素。下面是其他一些使用了扩展方括号的例子:

·   /PROJECT[.="MyProject"]——选中一个名为MyProjectPROJECT

·   /PROJECT[STATUS]——选中所有具有STATUS子元素的项目。

·   /PROJECT[STATUS="Critical"]——选中所有那些具有STATUS子元素,且该子元素包含字符串值"Critical"的项目。

组合索引地址

XPath规范定义了很少的几个寻址机制,并且它们还可以按照各种方法结合起来使用。由此,XPath为一个相对简单的规范提供了十分丰富的表现力。本节展示了另外两种有趣的组合:

·   LIST[@type="ordered"][3]——选中所有类型为"ordered"LIST元素,并返回其中的第三个。

·   LIST[3][@type="ordered"]——选中第三个LIST元素,但前提是它的类型为"ordered"

注意:XPath规范的第2.5节中列出了更多的地址运算符组合。这无疑是这个用于定义XSLT转换的规范中最有用的一节。

通配符

根据定义,无限制条件的XPath表达式选中一组与指定模式匹配的XML节点。例如,/HEAD与所有的顶级HEAD条目匹配,而/HEAD[1]只匹配其中的第一个。8-1列出了XPath表达式中可用的通配符,以扩展模式匹配的范围。

 8-1  XPath通配符

通配符

含义

*

匹配所有的元素节点(而非属性或者文本)

node()

匹配所有类型的节点:文本节点、属性节点、处理指令节点、命名空间节点或注释节点

@*

匹配所有的属性节点

比如在项目数据库的例子中, /*/PERSON[.="Fred"]与所有包括FredPROJECTACTIVITY元素匹配。

扩展路径寻址

到目前为止,我们见过的所有模式已经精确地指定了分层结构中的级数。例如,/HEAD指定了分层结构中第一级的所有HEAD元素,而/*/*指定了分层结构中第二级中的所有元素。为了指定分层结构的中间级,可以使用双斜杠(//)。例如,XPath表达式//会选中文档中所有的paragraph元素,不管它们位于何处。

//模式还可用在路径内部。所以表达式/HEAD/LIST//PARA表示以/HEAD/LIST开始的子树中所有的段元素。

XPath数据类型和运算符

XPath表达式生成一组节点、一个字符串、一个布尔值(true/false),或者一个数字。8-2列出了XPath表达式中可用的运算符。

 8-2 XPath运算符

运算符

含义

|

表示二选一。例如,PARA|LIST选中所有的PARALIST元素

or, and

返回两个布尔值的或/

=, !=

于或者不等于,用于布尔值、字符串和数字

<, >, <=, >=

小于、大于、小于或等于、大于或等于——用于数字

+, -, *, div, mod

加、减、乘、浮点除、模(余数)

最后,表达式可以用圆括号隔开,所以不必担心它们的运算顺序。

注意:“运算符优先级”正是解决这一问题的术语,“a + b * c是表示(a+b) * c,还是a + (b*c)呢?”。(运算符优先级和上表中所描述的大致一样)。

元素的字符串值

在继续我们的研究之前,有必要了解一下如何确定更复杂元素的字符串值。现在就开始吧。

元素的字符串值是所有子孙文本节点级联在一起构成的,不管这些节点有多深。所以,对于像

<PARA>This paragraph contains a <B>bold</B> word</PARA> 这样的“混合模型”XML数据元素,

<PARA>的字符串值为"This paragraph contains a bold word"。尤其要注意<B><PARA>的子元素,并且包含在所有子元素中的文本级联在一起构成了该字符串值。

同样,有必要知道XPath在抽象数据模型中定义的文本是完全规范化的。所以不管XML结构中是包含实体引用&lt;还是CDATA部分中的"<",元素的字符串值都包含"<"字符。因此,当生成HTML或者具有XSLT样式表的XML时,"<"必须被转换成&lt;,或者包含在一个CDATA部分中。同样,"&"也需要转换成&amp;

XPath函数

本节最后将概括一下XPath函数。可以利用XPath函数选中一类节点,方法和使用前面见过的元素规范一样。其他函数返回字符串、数字或者布尔值。例如,表达式/PROJECT/text()得到PROJECT节点的字符串值。

很多函数依赖于当前的上下文。比如在上例中,用于每个text()函数调用的上下文是当前选中的PROJECT节点。

XPath函数太多了,这里不能一一详细描述。本节列出了可用的XPath函数,并总结了它们的用途。

注意:只要大致浏览一下该函数列表,知道里面有什么东西就行了。详细内容可以参考 XPath规范中的第4节。

节点集函数

很多XPath表达式选中了一组节点。本质上,它们返回了一个节点集(node-set)。有一个函数也完成同样的功能。

·   id(...)——返回具有指定ID的节点。

(只有在文档具有DTD时,元素才有ID。因为DTD规定了哪些属性具有ID类型。)

位置函数

这类函数返回基于位置的数值。

·   last()——返回最后一个元素的索引。

例如:/HEAD[last()]选中最后一个HEAD元素。

·   position()——返回索引位置。

例如:/HEAD[position() <= 5]选中前五个HEAD元素。

·   count(...)——返回元素的数目。

例如:/HEAD[count(HEAD)=0]选中所有无子标题的HEAD元素。

字符串函数

这类函数对字符串起作用或者返回字符串。

·   concat(stringstring, ...)——连接字符串值。

·   starts-with(string1string2)——string1string2开始,则返回真。

·   contains(string1string2)——若string1包含string2,则返回真。

·   substring-before(string1string2)——在string1中出现string2之前,返回string1的起始部分。

·   substring-after(string1string2)——在string1中出现string2之后,返回string1中的剩余部分。

·   substring(stringidx)——返回索引位置到结尾之间的子字符串,其中第一个字符的索引等于1

·   substring(stringidxlen)——返回从索引位置开始、具有特定长度的子字符串。

·   string-length()——返回上下文节点字符串值的大小。

上下文节点是指当前选定的节点——即XPath表达式选中的、其中应用了像string-length()这样的函数的节点。

·   string-length(string)——返回指定字符串的大小。

·   normalize-space()——返回当前节点的规范化字符串值(首尾都无空白,且连续的空白字符被转换成一个空格)。

·   normalize-space(string)——返回指定字符串的规范化字符串值。

·   translate(string1string2string3)——转换string1,用string3中的字符替换string2中相应的字符。

注意:XPath定义了三种方法来获得元素的文本:text()string(object)以及字符串值。其中字符串值暗含在像/PROJECT[PERSON="Fred"]这样的表达式中的元素名中。

布尔函数

这类函数对布尔值起作用或者返回布尔值。

·   not(...)——对指定的布尔值取反。

·   true()——返回真。

·   false()——返回假。

·   lang(string)——若上下文节点的语言(由xml:Lang属性指定)与指定语言相同(或者是它的子语言),返回真。例如:Lang("en")对于<PARA_xml:Lang="en">...</PARA>为真。

数值函数

这类函数对数值其作用或返回数值。

·   sum(...)——返回特定节点组中各个节点数值的总和。

·   floor(N)——返回不超过N的最大整数。

·   ceiling(N)——返回大于N的最小整数。

·   round(N)——返回最接近N的整数。

 转换函数

这类函数将一种数据类型转换成另一种。

·   string(...)——返回数字、布尔值或者节点组的字符串值。

·   boolean(...)——返回数字、字符串或节点组的布尔值(一个非零数字、非空节点组和非空的字符串都为真)。

·   number(...)——返回布尔值、字符串或节点组的数值(真为1,假为0,包含某个数字的字符串的值为该数字本身,节点组的值是从它的字符串值转换而来)。

命名空间函数

这类函数能确定节点的命名空间特征。

·   local-name()——返回当前节点除命名空间前缀之外的名称。

·   local-name(...)——返回指定节点组除命名空间前缀之外的名称。

·   namespace-uri()——返回从当前节点开始的命名空间URI

·   namespace-uri(...)——返回从指定节点组中第一个节点开始的命名空间URI

·   name()——返回当前节点的扩展名(URI加本地名)。

·   name(...)——返回指定节点组中第一个节点的扩展名(URI加本地名)。

小结

XPath运算符、函数、通配符和节点寻址机制可以按照各种方式进行组合。有了前面的介绍,你在指定特定用途的模式时应该很得心应手。

本文转自kenty博客园博客,原文链接http://www.cnblogs.com/kentyshang/archive/2007/01/09/615757.html如需转载请自行联系原作者


kenty

相关文章
|
8月前
|
XML JSON JavaScript
XML语言
XML语言
62 0
|
XML JSON Go
Go 语言入门很简单:Go 处理 XML 文件(下)
先来看一看如何读取本地 XML 文件,同 JSON 数据类似,Go 同样需要一个结构体来接收 XML 的数据。
|
XML JSON Go
Go 语言入门很简单:Go 处理 XML 文件(上)
先来看一看如何读取本地 XML 文件,同 JSON 数据类似,Go 同样需要一个结构体来接收 XML 的数据。
|
XML 存储 前端开发
XML语言的基本语法-Java Web
XML语言的基本语法-Java Web
133 0
XML语言的基本语法-Java Web
|
XML SQL 关系型数据库
PostgreSQL 10.1 手册_部分 II. SQL 语言_第 9 章 函数和操作符_9.14. XML 函数
9.14. XML 函数 9.14.1. 产生 XML 内容 9.14.2. XML 谓词 9.14.3. 处理 XML 9.14.4. 将表映射到 XML 本节中描述的函数以及类函数的表达式都在类型xml的值上操作。
1156 0
|
存储 XML 关系型数据库
PostgreSQL 10.1 手册_部分 II. SQL 语言_第 8 章 数据类型_8.13. XML类型
8.13. XML类型 8.13.1. 创建XML值 8.13.2. 编码处理 8.13.3. 访问XML值 xml数据类型可以被用来存储XML数据。它比直接在一个text域中存储XML数据的优势在于,它会检查输入值的结构是不是良好,并且有支持函数用于在其上执行类型安全的操作,参见第 9.14 节。
1686 0
|
12天前
|
XML Java 数据库连接
mybatis中在xml文件中通用查询结果列如何使用
mybatis中在xml文件中通用查询结果列如何使用
9 0
|
14天前
|
XML JavaScript 前端开发
xml文件使用及解析
xml文件使用及解析
|
1月前
|
XML C# 数据格式
使用C#操作XML文件
使用C#操作XML文件
11 0
|
1月前
|
Java
java实现遍历树形菜单方法——映射文件VoteTree.hbm.xml
java实现遍历树形菜单方法——映射文件VoteTree.hbm.xml
9 0