xsl本身就是一个构型良好的xml,它能够把一个xml文档转换成另外一个xml文档,或者转换成文本文件、html文件等等。这里就是利用xsl来动态的生成我们想要的java文件(从某种角度看,java代码其实也就是一个文本文件),希望能够通过这篇文章,看到xml以及相关的技术所具有的强大能力!
这里首先给一个xml例子,我们将通过一个xsl从该xml文件中抽取有用的信息来生成java代码(实际上是一个javabean):
[code]
<?xml version="1.0" encoding="ISO-8859-1" ?>
<bean>
<name>Product</name>
<comments>This bean represents a product that thecompany
offers to its customers</comments>
<property>
<name>code</name>
<type>int</type>
<comments>the productinventory code</comments>
</property>
<property>
<name>name</name>
<type>String</type>
<comments>the productname</comments>
</property>
<property>
<name>testedOnAnimals</name>
<type>boolean</type>
<comments>the flag thatindicates if the product was
tested on animals</comments>
</property>
<property>
<name>availableSince</name>
<type>java.util.Date</type>
<comments>the date whenthe company started offering this
product to its customers</comments>
</property>
</bean>
[/code]
下面我就直接给出转换的xsl,如果大家对xsl不是很了解的话,可以先看一些资料,了解之后就会明白了。我在里面稍微做了些注释:
[code]
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:java="http://xml.apache.org/xslt/java"
exclude-result-prefixes="java">
<!--这里就是指定通过这个xsl所转换的结果的类型,是text格式-->
<xsl:output method = "text"/>
<!--xslt使用模版来处理xml中的节点-->
<xsl:template match="bean">
/**
* <xsl:value-of select="comments"/>//这里是获取xml文档中的节点值
* This class has been generated by the XSLT processor from the
metadata
*/
public class <xsl:value-of select="name"/> {
/**
* Creates a new instance of the <xsl:value-of
select="name"/> bean
*/
public <xsl:value-of select="name"/>(){}
<xsl:apply-templates select="property"/>
}
</xsl:template>
<xsl:template match="property">
private <xsl:value-ofselect="type"/>
<xsl:text> </xsl:text>//输出文本,这里是输出一个空格
<xsl:value-of select="name"/>;
<xsl:variable name="name"select="name"/>//定义xsl中要使用的变量
<xsl:variable name="cname"select="java:Capitalizer.capitalize($name)"/>//这里使用了xsltextensions,它可以允许在xslt中直接引用java中方法,非常方便。
/**
* Sets <xsl:value-ofselect="comments"/>
* @param <xsl:value-ofselect="name"/> is <xsl:value-of
select="comments"/>
*/
public void set<xsl:value-ofselect="$cname"/>(<xsl:value-
of select="type"/> <xsl:text></xsl:text><xsl:value-
of select="name"/>) {
this.<xsl:value-ofselect="name"/> = <xsl:value-of
select="name"/>;
}
/**
* Returns <xsl:value-ofselect="comments"/>
* @return <xsl:value-ofselect="comments"/>
*/
public <xsl:value-ofselect="type"/><xsl:text></xsl:text>
<xsl:apply-templatesselect="type"/><xsl:value-of
select="$cname"/>() {
return <xsl:value-of select="name"/>;
}
</xsl:template>
<xsl:template match="type">
<xsl:variable name="type"select="."/>
<xsl:choose>
<xsl:whentest="$type='boolean'">is</xsl:when>
<xsl:otherwise>get</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
[/code]
好了,完成以上工作之后,只要在cmd中,输入如下的命令行,就可以获得我们想要的结果了:
java org.apache.xalan.xslt.Process -in xmlSource -xsl stylesheet-out outputfile
这里列出结果:
[code]
/**
* This bean represents a product that the company offers to its
customers
* This class has been generated by the XSLT processor from the
metadata
*/
public class Product {
/**
* Creates a new instance of the Product bean
*/
public Product() {}
private int code;
/**
* Sets the product inventory code
* @param code is the product inventory code
*/
public void setCode(int code) {
this.code =code;
}
/**
* Returns the product inventory code
* @return the product inventory code
*/
public int getCode() {
return code;
}
private String name;
/**
* Sets the product name
* @param name is the product name
*/
public void setName(String name) {
this.name =name;
}
/**
* Returns the product name
* @return the product name
*/
public String getName() {
return name;
}
private boolean testedOnAnimals;
/**
* Sets the flag that indicates if the product wastested on animals
* @param testedOnAnimals is the flag that indicates ifthe product
was tested on animals
*/
public void setTestedOnAnimals(boolean testedOnAnimals){
this.testedOnAnimals =testedOnAnimals;
}
/**
* Returns the flag that indicates if the productwas tested on
animals
* @return the flag that indicates if the productwas tested on
animals
*/
public boolean isTestedOnAnimals() {
return testedOnAnimals;
}
private java.util.Date availableSince;
/**
* Sets the date when the company started offeringthis product to
its customers
* @param availableSince is the date when thecompany started
offering this product to its customers
*/
public void setAvailableSince(java.util.DateavailableSince) {
this.availableSince =availableSince;
}
/**
* Returns the date when the company startedoffering this product
to its customers
* @return the date when the company startedoffering this product
to its customers
*/
public java.util.Date getAvailableSince() {
return availableSince;
}
}
[/code]
总结:
1. 在熟悉了xsl的基本使用之后,理解以上的内容并不是困难;
2. 这样做是比较适合预先知道了某些逻辑功能,但由于某种原因,需要动态生成,或者是为了节省不必要的重复工作,可以通过它自动生成代码;
3. 修改这个xsl比较方便。
java xsl转换方法
XSL是指可扩展样式表语言 (EXtensible Stylesheet Language),是一种用于以可读格式呈现 XML 数据的语言。XSLT(EXtensible Stylesheet Language Transformation)可以将XML文档转换为其他格式,比如方便阅读的HTML或者纯文本。
要实现XSL转换,首先要提供XSLT样式表,它描述了XML文档像某种其他格式换换的规则,XSLT处理器将读入XML文档和样式表,并产生所要的输出。
看一段XML文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
现在需要输出一张HTML表格:
1 2 3 4 5 6 7 8 9 10 11 |
|
这里我们重点不在如何书写XSLT上,我们只关心Java如何使用XSL进行转换。更多关于XSL的见http://www.w3.org/TR/xslt.
XSLT样式表的格式如下:
1 2 3 4 5 6 7 8 9 |
|
在上面的例子中,需要把XML转换为HTML,所以这里使用xsl:output=”html”,另外还有两种有效的设置xml和text。
看一段简单的XSL样式表的片段:
1 2 3 |
|
match的属性值是一个XPath表达式,该片段的作用为,每遇到一个XPath集/staff/employee的节点时:
1. 产生字符串<tr>
2. 对于要处理的子元素继续应用该模板(template)
3. 当处理所有子元素后,产生字符串</tr>
这段代码就用于为每个雇员记录生成HTML表格的行标记。
接着看如何处理雇员记录信息:
1 2 3 |
|
这里将产生HTML标签<td>…</td>,并且请求处理器地归访问name元素的子节点。在这里它只有一个子节点——文本节点,当处理器访问该节点的时候,产生文本内容。
处理属性就相对复杂一点:
1 2 3 4 |
|
当处理hiredate时候,将产生:
1. 字符串<td>
2. year属性值
3. 连接符-
4. month属性值
5. 连接符-
6. day属性值
7. 连接符-
8. 字符串</td>
xsl:value-of语句用户计算节点集的字符串值,select属性值为XPath,提供计算的节点集。
完整的看看整个将XML转换为HTML表格的XSL样式表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
再看看一个将XML转换为TXT文本的样式表:
<?xmlversion="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:outputmethod="text"/>
<xsl:templatematch="/staff/employee">
employee.<xsl:value-ofselect="position()"/>.name=<xsl:value-ofselect="name/text()"/>
employee.<xsl:value-ofselect="position()"/>.salary=<xsl:value-ofselect="salary/text()"/>
employee.<xsl:value-ofselect="position()"/>.hiredate=<xsl:value-ofselect="hiredate
/@year"/>-<xsl:value-ofselect="hiredate/@month"/>-<xsl:value-ofselect="hiredate/@day"/>
</xsl:template>
</xsl:stylesheet>
TXT的输出结果为:
employee.1.name=Carl Cracker
employee.1.salary=75000.0
employee.1.hiredate=1987-12-15
employee.2.name=Harry Hacker
employee.2.salary=50000.0
employee.2.hiredate=1989-10-1
employee.3.name=Tony Tester
employee.3.salary=40000.0
employee.3.hiredate=1990-3-15
看看如何使用Java进行转换:
File styleSheet = newFile(filename);
StreamSource styleSource = newStreamSource(styleSheet);
Transformer t =TransformerFactory.newInstance().newTransformer(styleSource);
t.transform(source, result);
line 249
transform的第一个参数为Source,它可以是:
DOMSource
SAXSource
StreamSource
比如使用DOM树节点进行转换:
1 | t.transform(new DOMSource(doc), result); |
第二个参数为Resout,它可以是:
DOMResult
SAXResult
StreamResult
比如把转换结果存储到DOM树中:
1 2 | Document doc = builder.newDocument(); t.transform(source, new DOMResult(doc)); |
存储到文件中:
1 | t.transform(source, new StreamResult(file)); |
看一个完整的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.StringTokenizer;
import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource;
import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl;
/** * This program demonstrates XSL transformations. It applies a transformation to * a set of employee records. The records are stored in the file employee.dat * and turned into XML format. Specify the stylesheet on the command line, e.g. * java TransformTest makeprop.xsl */ public class TransformTest { public static void main(String[] args) throws Exception { String filename; if (args.length > 0) filename = args[0]; else filename = "makehtml.xsl"; File styleSheet = new File(filename); StreamSource styleSource = new StreamSource(styleSheet);
Transformer t = TransformerFactory.newInstance().newTransformer( styleSource); t.transform(new SAXSource(new EmployeeReader(), new InputSource( new FileInputStream("employee.dat"))), new StreamResult( System.out)); } }
/** * This class reads the flat file employee.dat and reports SAX parser events to * act as if it was parsing an XML file. */ class EmployeeReader implements XMLReader { public void parse(InputSource source) throws IOException, SAXException { InputStream stream = source.getByteStream(); BufferedReader in = new BufferedReader(new InputStreamReader(stream)); String rootElement = "staff"; AttributesImpl atts = new AttributesImpl();
if (handler == null) throw new SAXException("No content handler");
handler.startDocument(); handler.startElement("", rootElement, rootElement, atts); String line; while ((line = in.readLine()) != null) { handler.startElement("", "employee", "employee", atts); StringTokenizer t = new StringTokenizer(line, "|");
handler.startElement("", "name", "name", atts); String s = t.nextToken(); handler.characters(s.toCharArray(), 0, s.length()); handler.endElement("", "name", "name");
handler.startElement("", "salary", "salary", atts); s = t.nextToken(); handler.characters(s.toCharArray(), 0, s.length()); handler.endElement("", "salary", "salary");
atts.addAttribute("", "year", "year", "CDATA", t.nextToken()); atts.addAttribute("", "month", "month", "CDATA", t.nextToken()); atts.addAttribute("", "day", "day", "CDATA", t.nextToken()); handler.startElement("", "hiredate", "hiredate", atts); handler.endElement("", "hiredate", "hiredate"); atts.clear();
handler.endElement("", "employee", "employee"); }
handler.endElement("", rootElement, rootElement); handler.endDocument(); }
public void setContentHandler(ContentHandler newValue) { handler = newValue; }
public ContentHandler getContentHandler() { return handler; }
// the following methods are just do-nothing implementations public void parse(String systemId) throws IOException, SAXException { }
public void setErrorHandler(ErrorHandler handler) { }
public ErrorHandler getErrorHandler() { return null; }
public void setDTDHandler(DTDHandler handler) { }
public DTDHandler getDTDHandler() { return null; }
public void setEntityResolver(EntityResolver resolver) { }
public EntityResolver getEntityResolver() { return null; }
public void setProperty(String name, Object value) { }
public Object getProperty(String name) { return null; }
public void setFeature(String name, boolean value) { }
public boolean getFeature(String name) { return false; }
private ContentHandler handler; } |