从命令行转换
从命令行运行转换时,使用XSLTC很有意义。虽然Xalan解释转换器也包含一个命令行机制,但它不能像XSLTC那样,将预编译过的字节码保存为translet,以留作稍后之用。
从命令行运行XSLTC分两个步骤:
1. 编译translet。
2. 在数据上运行编译过的translet。
注意:关于这个主题的更多信息,请参见http://xml.apache.org/xalan-j/xsltc_usage.html上的用法指南。
编译translet
为了将article3.xsl样式表编译成translet,请执行下列命令:
java org.apache.xalan.xsltc.cmdline.Compile article3.xsl
注意:对于Java平台的1.3版,还需要包含合适的类路径设置,如编译并运行程序中所示。
结果为一个名为article3.class的类文件(translet)。
下面是编译translet时可以指定的一些参数。
java org.apache.xalan.xsltc.cmdline.Compile
-o transletName -d directory -j jarFile
-p packageName {-u stylesheetURI | stylesheetFile }
其中:
·
-o transletName
指定了生成的translet类(输出类)的名称。后缀.class是可选的。如果没有,会被样式表参数自动添加到指定的名称中。
·
-d directory
指定了目标目录(默认为当前的工作目录)。
·
-j jarFile
将生成的translet类文件输出到一个名为jarFile.jar的JAR文件中。使用该选项时,只创建JAR文件。
·
-p packageName
为生成的translet类指定了一个包名。
·
-u stylesheetURI
指定了具有URI,比如http://myserver/stylesheet1.xsl的样式表。
·
stylesheetFile
(无标志)样式表文件的路径名。
运行translet
为了在示例文件article3.xml上运行编译过的translet,请执行下列命令:
java org.apache.xalan.xsltc.cmdline.Transform
article3.xml article3
注意:如果是在1.3版的Java平台上运行translet,还需要设置类路径,如编译并运行程序中所示。
该命令将当前目录添加到类路径中,以便能找到该translet。输出在System.out中。
下面是运行translet时可以指定的一些参数:
java org.apache.xalan.xsltc.cmdline.Transform
{-u documentURI | documentFilename}
className [name=value...]
其中:
·
-u documentURI
指定了具有URI的XML输入文档。
·
documentFilename
为XML输入文档指定了文件名。
·
className
执行转换的translet。(这里不能指定后缀.class,必须像在运行Java应用时那样省略它。)
·
name=value ...
可选的一个或多个样式表参数的集合,被指定为名称-值对。
使用过滤器链连接各个转换
创建过滤器链有时很有用——所谓过滤器链是指很多XSLT转换的连接,在这个连接中一个转换的输出是下一个的输入。本节将向你展示如何做到这一点。
编写程序
首先编写一个程序来进行过滤。该示例将展示完整的源代码,但你可以选用正在使用的其中一个程序作为基础,以便让事情变得更容易。
注意:这里描述的代码包含在FilterChain.java中。
该示例程序包含能识别各个类的包位置的导入语句。
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.XMLFilter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
该程序还包含你过去常使用的标准错误处理程序。它们如下所示,也正是这样它们才同时被集中在一个地方。
}
catch (TransformerConfigurationException tce) {
// Error generated by the parser
System.out.println ("* Transformer Factory error");
System.out.println(" " + tce.getMessage() );
// Use the contained exception, if any
Throwable x = tce;
if (tce.getException() != null)
x = tce.getException();
x.printStackTrace();
}
catch (TransformerException te) {
// Error generated by the parser
System.out.println ("* Transformation error");
System.out.println(" " + te.getMessage() );
// Use the contained exception, if any
Throwable x = te;
if (te.getException() != null)
x = te.getException();
x.printStackTrace();
}
catch (SAXException sxe) {
// Error generated by this application
// (or a parser-initialization error)
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
}
catch (ParserConfigurationException pce) {
// Parser with specified options can't be built
pce.printStackTrace();
}
catch (IOException ioe) {
// I/O error
ioe.printStackTrace();
}
在导入语句和错误处理之间,该程序的核心部分由如下代码组成:
public static void main (String argv[])
{
if (argv.length != 3) {s
System.err.println (
"Usage: java FilterChain style1 style2 xmlfile");
System.exit (1);
}
try {
// Read the arguments
File stylesheet1 = new File(argv[0]);
File stylesheet2 = new File(argv[1]);
File datafile = new File(argv[2]);
// Set up the input stream
BufferedInputStream bis = new
BufferedInputStream(newFileInputStream(datafile));
InputSource input = new InputSource(bis);
// Set up to read the input file (see Note #1)
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
SAXParser parser = spf.newSAXParser();
XMLReader reader = parser.getXMLReader();
// Create the filters (see Note #2)
SAXTransformerFactory stf =
(SAXTransformerFactory)
TransformerFactory.newInstance();
XMLFilter filter1 = stf.newXMLFilter(
new StreamSource(stylesheet1));
XMLFilter filter2 = stf.newXMLFilter(
new StreamSource(stylesheet2));
// Wire the output of the reader to filter1 (see Note #3)
// and the output of filter1 to filter2
filter1.setParent(reader);
filter2.setParent(filter1);
// Set up the output stream
StreamResult result = new StreamResult(System.out);
// Set up the transformer to process the SAX events generated
// by the last filter in the chain
Transformer transformer = stf.newTransformer();
SAXSource transformSource = new SAXSource(
filter2, input);
transformer.transform(transformSource, result);
} catch (...) {
...
注意:
1. 当前Xalan转换引擎需要一个能识别命名空间的SAX解析器。而XSLTC却无此要求。
2. 这个怪异的代码位只能由如下事实来解释:SAXTransformerFactory扩展了TransformerFactory,并添加了用于获取过滤器对象的方法。newInstance()方法是定义在TransformerFactory中的一个静态方法,它(很自然地)返回一个TransformerFactory对象。但实际上,它返回的是SAXTransformerFactory。所以,为了获得SAXTransformerFactory定义的额外方法,返回值必须被强制转换成实际的类型。
3. XMLFilter对象既是一个SAX读取器又是一个SAX内容处理程序。作为SAX读取器,它为任何已注册过的能接收SAX事件的对象生成SAX事件。作为内容处理程序,它消耗它的“父”对象生成的SAX事件。这个父对象也必然是一个SAX读取器。(要调用事件发生器,“父”对象必须在查看内部体系结构时有意义。而从外部视角来看,该名称看起来不太合适)。过滤器同时生成和消耗SAX事件的这一事实允许它们互相链接。
了解过滤器链的工作原理
上述代码展示了如何创建转换。图 8-2应该有助于理解执行该转换时发生了什么。
图
8-2 链状过滤器的运行
当创建转换器时,它是在SAXSource对象上传递的,该对象封装了一个读取器(这里是filter2)和一个输入流。同时我们还为转换器传递了一个到结果流的指针,其中它在结果流中定向它的输出。上图说明了调用转换器上的transform()时,究竟发生了什么。这些步骤的解释如下:
1. 转换器为filter2建立了一个内部对象以作为内容处理程序,并告诉它解析输入源。
2. 然后filter2将自己设置为filter1的内容处理程序,并告诉它解析输入源。
3. filter1然后再告诉parser对象解析输入源。
4. parser按照要求解析了输入源之后,就生成SAX事件并将其传递给filter1。
5. 作为内容处理程序的filter1处理这些事件并完成它的转换。然后,filter1又作为SAX读取器(XMLReader),将SAX事件发送给filter2。
6. filter2也一样,它向转换器的内容处理程序发送它的事件,该内容处理程序再生成输出流。
测试程序
为了测试该程序,需要在一小部分XML DocBook格式的基础上创建一个XML文件,并将其转换成这里所定义的ARTICLE格式。然后再应用这个ARTICLE样式表,以生成一个HTML版本。
注意:该例子使用docbookToArticle.xsl 和 article1c.xsl来处理small-docbook-article.xml。结果为filterout.html(浏览器可显示的版本为small-docbook-article-xml.html、docbookToArticle-xsl.html、 article1c-xsl.html和filterout-src.html)。关于DocBook文章格式的更好描述请参见O'Reilly Web页面。
首先创建一篇文章,该文章使用了XML DocBook格式的一个微小子集。
<?xml version="1.0"?>
<Article>
<ArtHeader>
<Title>Title of my (Docbook) article</Title>
</ArtHeader>
<Sect1>
<Title>Title of Section 1.</Title>
<Para>This is a paragraph.</Para>
</Sect1>
</Article>
下一步,创建一个样式表并将其转换成ARTICLE格式。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:output method="xml"/> (see Note #1)
<xsl:template match="/">
<ARTICLE>
<xsl:apply-templates/>
</ARTICLE>
</xsl:template>
<!-- Lower level titles strip element tag --> (see Note #2)
<!-- Top-level title -->
<xsl:template match="/Article/ArtHeader/Title"> (Note #3)
<TITLE> <xsl:apply-templates/> </TITLE>
</xsl:template>
<xsl:template match="//Sect1"> (see Note #4)
<SECT><xsl:apply-templates/></SECT>
</xsl:template>
<xsl:template match="Para">
<PARA><xsl:apply-templates/></PARA> (see Note #5)
</xsl:template>
</xsl:stylesheet>
注意:
1. 这次,样式表生成的是XML输出。
2. 后面的模板(对于顶级的标题元素)只匹配主标题。对于节标题,TITLE标签被去除。(由于没有模板转换管理这些标题元素,它们都被忽略。而它们包含的文本节点仍被作为XSLT内置模板规则的结果被回送——所以只有标签被忽略,而不是文本。其他更多内容如下所示)。
3. 来自DocBook文章头部的标题成为了ARTICLE标题。
4. 有编号的节标签被转换成纯SECT标签。
5. 由于该模板执行了一个大小写转换,所以Para就变成了PARA。
虽然没有明确提到,但XSLT事实上定义了很多内置的(默认)模板规则。完整列表如规范中的第5.8节所示。它们主要用于自动复制文本和属性节点,以及跳过注释和处理指令。它们还规定即使它们包含的标签没有模板,内部元素也要被处理。这就是即使节标题没有被任何模板转换,其中的文本节点也被处理的原因。
这时,运行FilterChain程序,并将上面的样式表(docbookToArticle.xsl)、ARTICLE样式表(article1c.xsl)和小DocBook文件(small-docbook-article.xml)按照顺序传递给它。结果应该如下所示:
<html>
<body>
<h1 align="center">Title of my (Docbook) article</h1>
<h2>Title of Section 1.</h2>
<p>This is a paragraph.</p>
</body>
</html>
注意:该输出是利用JAXP 1.0生成的。但是,该链中的第一个过滤器目前没有转换输入文件中的任何标签。除非这一缺陷得到修复,否则你看到的输出将由HTML输出中的连接纯文本组成,比如"Title of my (Docbook) article Title of Section 1. This is a
paragraph."。
结论
恭喜!你已经完成了本XSLT教程。利用XML和XSLT可以做很多事情,并且现在你可以开始探索更多正等待你去发现的有趣的可能性了。
更多信息
关于XSL样式表、XSLT和转换引擎的更多信息,请参见:
·
关于XSLT的一个不错的介绍,它以一个简单的HTML页面开始并使用XSLT来逐步自定义它: http://www.xfront.com/rescuing-xslt.html
·
可扩展的样式表语言(XSL): http://www.w3.org/Style/XSL/
·
XML路径语言: http://www.w3.org/TR/xpath
·
Xalan转换引擎: http://xml.apache.org/xalan-j/
·
XSLTC转换引擎: http://xml.apache.org/xalan-j/
·
XSLTC的使用技巧:http://xml.apache.org/xalan-j/xsltc_usage.html
·
利用XSLTC设计样式表以最大化性能:http://xml.apache.org/xalan-j/xsltc/xsltc_performance.html
|