410 likes | 536 Views
J2EE —— 第 7 章 Extensible Stylesheet Language Transformations (XSLT). XSL 、 XSLT 和 XPath 简介. XSL-FO: 字体大小、页面布局、对象显示 XSLT: 从 XML 到某种其它格式的转换 XPath: 指定通向某个元素的路径 javax.xml.transform javax.xml.transform.dom javax.xml.transform.sax javax.xml.transform.stream. XPath 如何工作.
E N D
J2EE——第7章 Extensible Stylesheet Language Transformations (XSLT)
XSL、XSLT和XPath简介 • XSL-FO:字体大小、页面布局、对象显示 • XSLT:从XML到某种其它格式的转换 • XPath:指定通向某个元素的路径 • javax.xml.transform • javax.xml.transform.dom • javax.xml.transform.sax • javax.xml.transform.stream
XPath如何工作 • XPath规范定义了一个抽象文档模型,该文档模型定义了几种类型的节点:Root, Element,Text, Attribute,Comment Processing instruction, Namespace • XSLT/XPath数据模型:包含各种节点的树 <xsl:template match="//LIST"> ... </xsl:template>
基本XPath寻址 • 正斜杠(/)用作路径分隔符 • 从文档的根开始的绝对路径以/开始 • 从指定位置开始的相对路径可以以任何其它符号开始 • 双句点(..)表示当前节点的父节点 • 单句点(.)表示当前节点
基本XPath表达式 • PROJECT[.=“MyProject”] • PROJECT[STATUS] • PROJECT[STATUS=“Critical”] • LIST[@type=“ordered”][3] • LIST[3][@type=“ordered”] • *匹配任何Element节点 • node()匹配任何类型的任何节点 • @*匹配任何属性节点 • /HEAD/LIST//PARA
元素的字符串值 <PARA>This paragraph contains a <B>bold</B> word</PARA> • PARA/text() • This paragraph contains a bold word
XPath函数 • 节点集函数 • id(…) • 位置函数 • last():如/HEAD[last()] • position():如/HEAD[position()<=5] • count(…):如/HEAD[count(HEAD)=0]
字符串函数 • concat(string, string, ...): • contains(string1, string2 • substring-before(string1, string2) • substring-after(string1, string2) • substring(string, idx) • substring(string, idx, len) • string-length() • string-length(string) • normalize-space() • normalize-space(string) • translate(string1, string2, string3):
其它函数 • Boolean函数 • not(...) • true() • false() • lang(string) • 数值函数 • sum(…) • floor(N) • ceiling(N) • round(N)
其它函数 • 转换函数 • string(…) • boolean(…) • number(…) • 名称空间函数 • local-name(), local-name(…) • namespace-uri(), namespace-uri(..) • name(), name(…)
把DOM作为XML文件写出 import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); DOMSource source = new DOMSource(document); StreamResult result = new StreamResult(System.out); transformer.transform(source, result);
写出DOM的子树 import org.w3c.dom.Node; import org.w3c.dom.NodeList; NodeList list = document.getElementsByTagName("slide"); Node node = list.item(0); DOMSource source = new DOMSource(node); <?xml version="1.0" encoding="UTF-8"?> <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide>
从任一数据结构生成XML xmozillanickname: Fred mail: Fred@barneys.house xmozillausehtmlmail: TRUE givenname: Fred sn: Flintstone telephonenumber: 999-Quarry homephone: 999-BedrockLane facsimiletelephonenumber: 888-Squawk pagerphone: 777-pager cellphone: 555-cell
准备工作 import org.xml.sax.*; import org.xml.sax.helpers.AttributesImpl; public class AddressBookReader implements XMLReader { ContentHandler handler; String nsu = ""; // NamespaceURI Attributes atts = new AttributesImpl(); String rootElement = "addressbook"; String indent = "\n "; // for readability! public void parse (InputSource input) throws IOException, SAXException{ java.io.Reader r = input.getCharacterStream(); BufferedReader br = new BufferedReader(r);
生成SAX事件 if (handler==null) { throw new SAXException("No content handler"); } handler.startDocument(); handler.startElement(nsu, rootElement, rootElement, atts); output("nickname", "xmozillanickname", line); line = br.readLine(); ... output("cell", "cellphone", line); handler.ignorableWhitespace("\n".toCharArray(), 0, 1); handler.endElement(nsu, rootElement, rootElement); handler.endDocument();
元素SAX事件 void output(String name, String prefix, String line) throws SAXException { int startIndex = prefix.length() + 2; // 2=length of ": " String text = line.substring(startIndex); int textLength = line.length() - startIndex; handler.ignorableWhitespace(indent.toCharArray(), 0, indent.length()); handler.startElement(nsu, name, name /*"qName"*/, atts); handler.characters(text.toCharArray(), startIndex, textLength); handler.endElement(nsu, name, name); }
把解析器用作SAXSource import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import javax.xml.transform.sax.SAXSource; AddressBookReader saxReader = new AddressBookReader(); Transformer transformer = tFactory.newTransformer(); FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); InputSource inputSource = new InputSource(br); SAXSource source = new SAXSource(saxReader, inputSource); StreamResult result = new StreamResult(System.out); transformer.transform(source, result);
用XSLT转换XML数据 <?xml version="1.0"?> <ARTICLE> <TITLE>A Sample Article</TITLE> <SECT>The First Major Section <PARA>This section will introduce a subsection.</PARA> <SECT>The Subsection Heading <PARA>This is the text of the subsection. </PARA> </SECT> </SECT> </ARTICLE>
编写XSLT转换 <?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <html><body> <xsl:apply-templates/> </body></html> </xsl:template> … </xsl:stylesheet> • 使用html输出方式时, <将输出为<
处理<TITLE>和<SECT> <xsl:template match="/ARTICLE/TITLE"> <h1 align="center"><xsl:apply-templates/></h1> </xsl:template> <xsl:template match="/ARTICLE/SECT"> <h2><xsl:apply-templates select="text()|B|I|U|DEF|LINK"/></h2> <xsl:apply-templates select="SECT|PARA|LIST|NOTE"/> </xsl:template> <xsl:template match="/ARTICLE/SECT/SECT"> <h3><xsl:apply-templates select="text()|B|I|U|DEF|LINK"/></h3> <xsl:apply-templates select="SECT|PARA|LIST|NOTE"/> </xsl:template> </xsl:stylesheet>
处理过深嵌套错误和<PARA> <xsl:template match="/ARTICLE/SECT/SECT/SECT"> <xsl:message terminate="yes"> Error: Sections can only be nested 2 deep. </xsl:message> </xsl:template> <xsl:template match="PARA"> <p><xsl:apply-templates/></p> </xsl:template> </xsl:stylesheet>
编写基本的程序 import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamResult; File stylesheet = new File(argv[0]); File datafile = new File(argv[1]); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(datafile); StreamSource stylesource = new StreamSource(stylesheet); Transformer transformer = Factory.newTransformer(stylesource); DOMSource source = new DOMSource(document); StreamResult result = new StreamResult(System.out); transformer.transform(source, result);
转换结果 <html> <body> <h1 align="center">A Sample Article</h1> <h2>The First Major Section </h2> <p>This section will introduce a subsection.</p> <h3>The Subsection Heading </h3> <p>This is the text of the subsection. </p> </body> </html>
剪裁空白 <xsl:strip-space elements="SECT"/> <xsl:template match="text()"> <xsl:value-of select="normalize-space()"/> </xsl:template> <html> <body> <h1 align="center">A Sample Article</h1> <h2>The First Major Section</h2> <p>This section will introduce a subsection.</p> <h3>The Subsection Heading</h3> <p>This is the text of the subsection.</p> </body> </html>
处理其余的结构元素 <?xml version="1.0"?> <ARTICLE> <TITLE>A Sample Article</TITLE> <SECT>The First Major Section ... </SECT> <SECT>The Second Major Section <PARA>This section adds a LIST and a NOTE. </PARA> <PARA>Here is the LIST: <LIST type="ordered"> <ITEM>Pears</ITEM> <ITEM>Grapes</ITEM> </LIST> </PARA> <PARA>And here is the NOTE: <NOTE>Don't forget to go to the hardware store on your way to the grocery! </NOTE> </PARA> </SECT> </ARTICLE>
修改XSLT <xsl:template match="PARA"> <p><xsl:apply-templates select="text()|B|I|U|DEF|LINK"/></p> <xsl:apply-templates select="PARA|LIST|NOTE"/> </xsl:template> <xsl:template match="LIST"> <xsl:if test="@type='ordered'"> <ol> <xsl:apply-templates/> </ol> </xsl:if> <xsl:if test="@type='unordered'"> <ul> <xsl:apply-templates/> </ul> </xsl:if> </xsl:template> </xsl:stylesheet>
处理<ITEM>和<NOTE> <xsl:template match="ITEM"> <li><xsl:apply-templates/> </li> </xsl:template> <xsl:template match="NOTE"> <blockquote><b>Note:</b><br/> <xsl:apply-templates/> </blockquote> </xsl:template> • 当多个模板都匹配时,最后出现的模板优先
运行结果 … <h2>The Second Major Section</h2> <p>This section adds a LIST and a NOTE.</p> <p>Here is the LIST:</p> <ol> <li>Pears</li> <li>Grapes</li> </ol> <p>And here is the NOTE:</p> <blockquote> <b>Note:</b> <br>Don't forget to go to the hardware store on your way to the grocery! </blockquote>
处理内联(内容)元素 <SECT>The <I>Third</I> Major Section <PARA>In addition to the inline tag in the heading, this section defines the term <DEF>inline</DEF>, which literally means "no line break". It also adds a simple link to the main page for the Java platform (<LINK>http://java.sun.com</LINK>), as well as a link to the <LINK target="http://java.sun.com/xml">XML</LINK> page. </PARA> </SECT>
修改XSLT <xsl:template match="DEF"> <i><xsl:apply-templates/></i> </xsl:template> <xsl:template match="B|I|U"> <xsl:element name="{name()}"> <xsl:apply-templates/> </xsl:element> </xsl:template>
处理<LINK> <xsl:template name="htmLink"> <xsl:param name="dest" select="UNDEFINED"/> <xsl:element name="a"> <xsl:attribute name="href"> <xsl:value-of select="$dest"/> </xsl:attribute> <xsl:apply-templates/> </xsl:element> </xsl:template>
调用命名模板 <xsl:template match="LINK"> <xsl:if test="@target"> <xsl:call-template name="htmLink"> <xsl:with-param name="dest" select="@target"/> </xsl:call-template> </xsl:if> <xsl:if test="not(@target)"> <xsl:call-template name="htmLink"> <xsl:with-param name="dest"> <xsl:apply-templates/> </xsl:with-param> </xsl:call-template> </xsl:if> </xsl:template>
运行结果 ... <h2>The <I>Third</I> Major Section </h2> <p>In addition to the inline tag in the heading, this section defines the term <i>inline</i>, which literally means "no line break". It also adds a simple link to the main page for the Java platform (<a href="http://java. sun.com">http://java.sun.com</a>), as well as a link to the <a href="http://java.sun.com/xml">XML</a> page. </p>
XSLT的其它功能 • include, import • for-each • 生成编号 • 格式化编号 • 输出排序 • 基于模式的模板 <apply-template mode=“…”>
用Xalan从命令行转换 java org.apache.xalan.xslt.Process -IN article3.xml -XSL article3.xsl -OUT article3.html
用过滤器链连接转换 File stylesheet1 = new File(argv[0]); File stylesheet2 = new File(argv[1]); File datafile = new File(argv[2]); BufferedInputStream bis = new BufferedInputStream(newFileInputStream(datafile)); InputSource input = new InputSource(bis); SAXParserFactory.newInstance(); spf.setNamespaceAware(true); SAXParser parser = spf.newSAXParser(); XMLReader reader = parser.getXMLReader(); SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance(); XMLFilter filter1 = stf.newXMLFilter( new StreamSource(stylesheet1)); XMLFilter filter2 = stf.newXMLFilter( new StreamSource(stylesheet2)); filter1.setParent(reader); filter2.setParent(filter1); StreamResult result = new StreamResult(System.out); Transformer transformer = stf.newTransformer(); SAXSource transformSource = new SAXSource(filter2, input); transformer.transform(transformSource, result);
测试程序 <?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>
作为filter1的xsl文件 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform“ version="1.0“> <xsl:output method="xml"/> <xsl:template match="/"> <ARTICLE> <xsl:apply-templates/> </ARTICLE> </xsl:template> <xsl:template match="/Article/ArtHeader/Title"> <TITLE> <xsl:apply-templates/> </TITLE> </xsl:template> <xsl:template match="//Sect1"> <SECT><xsl:apply-templates/></SECT> </xsl:template> <xsl:template match="Para"> <PARA><xsl:apply-templates/></PARA> </xsl:template> </xsl:stylesheet>
过滤器链连接转换结果 <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>