转: http://blog.csdn.net/starchu1981/category/11683.aspx




XML和XSLT实现代码生成器(I)

摘要

       XMLXSLT为开发WEB应用提供了非常好的解决方案,然而,它们的能力不仅限制在WEB开发上,其实它们提供了很好的基于元数据(meta data)编程的模型,利用XML作为元数据并用XSLT就可以将它转换为任何想要的形式或其他数据。本文第一部分介绍了如何利用Java以及XMLXSLT实现代码生成器功能,,第二部分讨论了使用这种解决方案的优点和不足,以及如何改进该方案使用,本文同时还展示了JAXPJDOM API的使用。

介绍

       编写代码是程序员的日常工作,通常编写程序代码被认为是有创造性的工作,这也是很多人热爱编程的一大理由。然而有时人们不得不面对重复编写一些简单的,另人乏味的代码,最好的例子就是Java中的JavaBean,尤其是在J2EE应用中,程序员需要在Web层编写许多JavaBean和数据层(通常是EJB)交换数据,为每一个JavaBean编写get, set方法是十分机械而枯燥的工作。如果这些类似的工作能由机器自动完成,程序员就可以花费更多的努力在有创造的开发上了。代码生成器就是为了这个目的而出现的,基本上所有流行的IDE都或多或少的包含代码生成的能力。例如,在VC中创建项目时IDE生成MFC的基本框架代码以及Jbuilder高版本中自动生成JavaDoc注释的功能。要实现一个代码生成器,首先必须提供有关于生成什么代码的基本信息,也即元数据,然后程序提取这些元数据并自动生成实际的代码。不难想象,提供元数据的最好方法就是使用一种统一的,容易验证的而且便于提取的数据格式,XMLDTDXML Schema(可选)以及XSLT的组合正好提供了这一切。XML提供统一的数据,DTDXML Schema用于验证数据的有效性,而XSLT则用于提取XML元数据并进行转换。后面的部分将以一个JavaBean代码生成器为例,详细介绍如何将这些技术组合起来用于实际应用。

建立简易模型

       JavaBean是包含一组属性的简单Java类,通常包括字段定义,构造函数以及几对get/set方法。可以首先为XML元数据建立一个DTD表示它应包含的基本信息。列表1.1展示了一个这样的DTD模型。<?xml version="1.0" encoding="UTF-8"?>

<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com) by starchu1981 (melbourne university) -->

<!ELEMENT xgen (javabean?)>

<!ELEMENT javabean (name, package, implement*, property*)>

<!ELEMENT package (name, description?)>

<!ELEMENT name (#PCDATA)>

<!ELEMENT description (#PCDATA)>

<!ELEMENT implement (#PCDATA)>

<!ELEMENT property (name, exception*)>

<!ELEMENT exception (#PCDATA)>

<!ATTLIST property

       type CDATA #REQUIRED

       set (yes | no) #IMPLIED

       get (yes | no) #IMPLIED>

列表1.1

javabeanimplement子元素代表该Bean所实现的接口,当然也可定义一个extend子元素表明Bean所扩展的类,Property元素的属性列表还可以在以后加入isIndex属性用来表明该属性是否是一个index属性。由于DTD基本是自解释,所以就不一一详细说明了。DTD设计完成后就可以利用它来书写XML数据了。列表1.2是一个简单XML例子

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE xgen SYSTEM "../dtd/xgen-javabean.dtd">

<xgen>

    <javabean>

        <name>test2</name>

        <package>

            <name>com.xs.xgen.test</name>

            <description>Test For XGen Dtd and XML model</description>

        </package>

        <property type="java.lang.String" set="yes" get="yes">

            <name>description</name>

        </property>

        <property type="int" set="no" get="yes">

            <name>innerData</name>

            <exception>AccessNotAllowedException</exception>

        </property>

        <property type="javax.xml.transform.Source" set="yes" get="no">

            <name>source</name>

            <exception>SAXNotRecognizedException</exception>

            <exception>SAXNotSupportedException</exception>

        </property>

        <property type="int" set="no" get="no">

            <name>nonsenseData</name>

        </property>

    </javabean>

</xgen>

列表1.2






XMLXSLT实现代码生成器(II

XSLT处理元数据

       如前文所述,当建立元数据以后,就可以使用XSLTXML数据转换为实际的代码了,列表1.3展示了一个XSL文档,它将处理上述的XML元数据,完成转换工作。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <!Java代码是文本格式的,所以需要设定输出方法为testà

    <xsl:output method="text"/>

    <xsl:variable name="properties" select="/xgen/javabean/property"/>

    <xsl:template match="/">

        <xsl:apply-templates select="xgen"/>

    </xsl:template>

    <!匹配xgen元素 à

    <xsl:template match="xgen">

        <xsl:text>/*Generated By XGen Xingchen Chu@XS Group Copyright(c) Reserved*/</xsl:text>

        <xsl:apply-templates select="javabean"/>

    </xsl:template>

    <!匹配javabean元素,实际代码生成在此完成à

    <xsl:template match="javabean">

        <xsl:text>package </xsl:text>           <!输出包名à

        <xsl:value-of select="package/name"/>

        <xsl:text>;</xsl:text>

        <xsl:text>public class </xsl:text> <!输出JavaBean类名 à

        <xsl:value-of select="name"/>

        <xsl:text> implements </xsl:text>       <!输出实现的接口à

        <xsl:if test="implement">

            <xsl:apply-templates select="implement"/>

        </xsl:if>

        <xsl:text>java.io.Serializable</xsl:text>   <!每个JavaBean必须实现的接口à

        <xsl:text>{</xsl:text>

        <xsl:call-template name="printField"/> <!输出字段信息>

        <xsl:call-template name="printConstructor"/> <!输出构造函数à

        <xsl:apply-templates select="property"/>    <!输出所有属性的get和set方法à

        <xsl:text>}</xsl:text>

    </xsl:template>

    <!匹配implement元素,简单的输出其值并跟逗号à

    <xsl:template match="implement">

        <xsl:value-of select="text()"/><xsl:text>,</xsl:text>

    </xsl:template>

    <!匹配property元素,输出适当的方法à

    <xsl:template match="property">

        <xsl:if test="@set='yes'">

            <xsl:call-template name="printSetMethod">

                <xsl:with-param name="property" select="."/>

            </xsl:call-template>

        </xsl:if>

        <xsl:if test="@get='yes'">

            <xsl:call-template name="printGetMethod">

                <xsl:with-param name="property" select="."/>

            </xsl:call-template>

        </xsl:if>

    </xsl:template>

    <xsl:template name="printField">

        <xsl:for-each select="$properties">

            <xsl:text>private </xsl:text>

            <xsl:value-of select="@type"/>

            <xsl:text> </xsl:text>

            <xsl:value-of select="name"/>

            <xsl:text>=</xsl:text>

            <xsl:call-template name="printDefaultValue">    <!输出字段缺省值à

                <xsl:with-param name="type" select="@type"/>

            </xsl:call-template>

            <xsl:text>;</xsl:text>

        </xsl:for-each>

    </xsl:template>

    <xsl:template name="printConstructor">

        <xsl:text>public </xsl:text>

<xsl:value-of select="/xgen/javabean/name"/>

        <xsl:text>(</xsl:text> 

        <xsl:for-each select="$properties"> <!输出构造函数参数列à

            <xsl:value-of select="@type"/>

<xsl:text> </xsl:text>

<xsl:value-of select="name"/>

            <xsl:if test="position()&lt;last()">

                <xsl:text>,</xsl:text>

            </xsl:if>

        </xsl:for-each>

        <xsl:text>){</xsl:text>

        <xsl:for-each select="$properties"> <!输出构造函数主体à

            <xsl:text>this.</xsl:text>

<xsl:value-of select="name"/><xsl:text>=</xsl:text>

            <xsl:value-of select="name"/><xsl:text>;</xsl:text>

        </xsl:for-each>

        <xsl:text>}</xsl:text>

    </xsl:template>

 </xsl:stylesheet>

 

列表1.3

 




 

XMLXSLT实现代码生成器(III

 XSLT处理元数据(续)

   <!命名模板,打印set方法à

    <xsl:template name="printSetMethod">

        <xsl:param name="property"/>

        <xsl:text>public void set</xsl:text>

        <xsl:call-template name="translateHeadLetter"> <!属性首字母需大写à

            <xsl:with-param name="propertyName" select="name"/>

        </xsl:call-template>

        <xsl:text>(</xsl:text>

        <xsl:value-of select="@type"/>

        <xsl:text> </xsl:text>

        <xsl:value-of select="name"/>

        <xsl:text>)</xsl:text>

        <xsl:if test="exception">    <!输出任何方法抛出的异常 à

            <xsl:text>throws </xsl:text>

                    <xsl:apply-templates select="exception"/>

        </xsl:if>

        <xsl:text>{ this.</xsl:text>        <!set方法主体à

        <xsl:value-of select="name"/>

        <xsl:text>=</xsl:text>

        <xsl:value-of select="name"/>

        <xsl:text>;}</xsl:text>

    </xsl:template>

    <!命名模板,打印get方法à

    <xsl:template name="printGetMethod">

        <xsl:param name="property"/>

        <xsl:text>public </xsl:text>

        <xsl:value-of select="@type"/>

        <xsl:choose>

            <xsl:when test="@type='boolean' or @type='java.lang.Boolean'">

                <xsl:text> is</xsl:text>

            </xsl:when>

            <xsl:otherwise>

                <xsl:text> get</xsl:text>

            </xsl:otherwise>

        </xsl:choose>

        <xsl:call-template name="translateHeadLetter">

            <xsl:with-param name="propertyName" select="name"/>

        </xsl:call-template>

        <xsl:text>()</xsl:text>

        <xsl:if test="exception">

            <xsl:text>throws </xsl:text>

                    <xsl:apply-templates select="exception"/>

        </xsl:if>

        <xsl:text>{ return </xsl:text>

        <xsl:value-of select="name"/>

        <xsl:text>;}</xsl:text>

    </xsl:template>

    <xsl:template name="translateHeadLetter">

        <xsl:param name="propertyName"/>

        <xsl:variable name="length" select="string-length($propertyName)"/>

        <xsl:variable name="headLetter" select="substring($propertyName,1,1)"/>

<xsl:variable name="remainLetters" select="substring($propertyName,2,$length)"/>

<xsl:value-of

select="translate($headLetter,'abcdefghijklmnopqrstuvwxyz',

'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>

        <xsl:value-of select="$remainLetters"/>

    </xsl:template>

    <xsl:template name="printDefaultValue">

        <xsl:param name="type"/>

        <xsl:choose>

            <xsl:when test="contains($type,'int')">

                <xsl:text>0</xsl:text>

            </xsl:when>

            <xsl:when test="contains($type,'boolean')">

                <xsl:text>false</xsl:text>

            </xsl:when>

            <xsl:when test="contains($type,'long')">

                <xsl:text>0</xsl:text>

            </xsl:when>

            <xsl:when test="contains($type,'float')">

                <xsl:text>0</xsl:text>

            </xsl:when>

            <xsl:when test="contains($type,'char')">

                <xsl:text>''</xsl:text>

            </xsl:when>

            <xsl:when test="contains($type,'String')">

                <xsl:text>""</xsl:text>

            </xsl:when>

            <xsl:otherwise>

                <xsl:text>null</xsl:text>

            </xsl:otherwise>

        </xsl:choose>

    </xsl:template>

    <xsl:template match="exception">

        <xsl:value-of select="."/>

        <xsl:if test="position()&lt;last()">

            <xsl:text>,</xsl:text>

        </xsl:if>

    </xsl:template>

列表1.3续

不熟悉XSLT的读者可以参看[2]以便了解更多的信息。该XSL分析XML数据,针对匹配的元素将元数据转换为实际的Java代码。在支持XSLT的浏览器上如IE6可以直接键入XML文档的URL,就可以看见转换结果,注意:需要在XML中加入如下指令

<?xml-stylesheet type="text/xsl" href="../xsl/javabean.xsl"?>

这样经过简单的两个步骤,代码转换的功能已经基本实现,只要利用一个简单的Java小程序就可以完成该代码生成器的初始模型。

 

简单代码生成器

列表1.5显示了一个这样目的的Java类。

Package com.xs.xgen;

Import javax.xml.transform.*;

Import javax.xml.transform.stream.*;

/**

 * <p>Title: Code Generator based on XML and XSLT</p>

 * <p>Description: Beta Version For Code Generator</p>

 * <p>Copyright: xchu@Copyright (c) 2004</p>

 * <p>Company: XS Group</p>

 * @author Xingchen Chu

 * @version 0.1

 */

Public class SimpleCodeGenerator{

 public static void main(String [] args){

    if(args.length<3){

        System.err.println(Usage : java SimpleCodeGenerator [xml] [xsl] [output]);

        System.exit(1);

    }

    try{

     Source xmlSource=

          new javax.xml.transform.stream.StreamSource(new File(args[0]));

      javax.xml.transform.Source xslSource=

          new javax.xml.transform.stream.StreamSource(new File(args[1]));

      javax.xml.transform.Result result=

          new javax.xml.transform.stream.StreamResult(new File(args[2]);

     TransformerFactory factory = TransformerFactory.newInstance();

      Transformer transformer = factory.newTransformer(xslSource);

      Transformer.transform(xmlSource,result);

    }catch(Exception e){

      e.printStackTrace();

    }

 }

列表1.4

结果分析

       对于这个代码生成器来说,虽然基本的目的已经达到,机器已经完全可以自动的生成所有的代码,程序员只需要根据DTD编写一小段XML元数据即可,使用像XMLSpy这样的工具可以很容易编写出合适的XML元数据并可进行验证,然后使用java命令行即可得到想要的JavaBean类文件。而且如果想在现有的基础上添加更多的功能,比如支持索引属性,只需要稍微更改DTD以及XSL即可实现,如果还想为EJB生成基本接口文件,可以重新定义一个新的DTDXSL,而不需要改变任何一点的Java代码。

       然而,一切都还不完美。首先,XSLT的输出文本结果十分难阅读,因为XSLT在处理空格和缩近上能力有限,可读性好的结果文档是一个可以改进的方面;其次,程序员还是必须编写XML文件,并手动传递它和XSLT给代码生成器,这种静态方式可以被图形化的动态方式替代是更好的方案。本文的下一部分将说明这些问题并提出合适的解决方法。

 

 

References

1.      Java and XSLT Eric M. Burke O’Reilly & Associates,Inc 2001

2.      Essential XML Don Box, Aaron Skonnard & John Lam

Addison Wesley Longman, Inc. 2001



XMLXSLT实现代码生成器(IV

结果处理

       本文第一部分描述了如何使用静态XML文档和XSLT以及一个简单的Java转换程序实现基本的代码生成器,然而通过分析结果,我的实现至少还有两点是十分原始的,首先代码输出结果的格式非常不理想(参看图2.1),输出代码之间完全没有的空行、缩进,导致代码非常难以阅读,这就需要通过一个程序将原始结果过滤为符合阅读需求的Java源代码,可以将这一步称为代码美容。一种可选的方法是使用现存的产品自动清理Java代码,例如JIndent (http://www.jindent.com);另一种方法是自己动手美容代码,列表2.2显示了我的简单实现

Pic 2.1 Result of Generated Code(Using IE Browser)

package com.xs.xgen.util;

import java.io.*;

import java.util.*;

/**

 * <p>Title: Code Generator based on XML and XSLT</p>

 * <p>Description: Beta Version For Code Generator</p>

 * <p>Copyright: xchu@Copyright (c) 2004</p>

 * <p>University: Melbourne University</p>

 * @author Xingchen Chu

 * @version 0.1

 */

public class IndentUtil {

 /**

   * <description> add indent to the content of input file output </description>

   * @param java.io.File input

   * @param java.io.File output

   */

 public static void indentJavaSource(File input, File output){

try{

     //read all the content at one time and write them to the string buffer

      BufferedReader in = new BufferedReader(new FileReader(input));

      StringBuffer sb=new StringBuffer();

      String line=null;

      while((line=in.readLine())!=null){

        sb.append(line);

      }

      String content = sb.toString();

      FileWriter writer=new FileWriter(output);

indentContent(writer,content,0,0); //indent from the beginning of the content

    }catch(Exception e){

      throw new RuntimeException(e);

}finally{

     writer.close();

}

 }

 private static void indentContent(Writer writer,String content,

int begin,int indent)throws IOException{

    if(begin>content.length()-1){ //now the position is the end of the content

      writer.flush();

      return;

    }

    char currentChar = content.charAt(begin); //get the current char of the content

    if(currentChar=='}'){

      writer.write("\r\n");

      indent-=5;

      for(int j=0;j<indent;j++){

        writer.write(" ");

      }

writer.write(currentChar);

//check whether is the end of the class file

     if((begin+1)<content.length()&&content.charAt(begin+1)!=')'){

        writer.write("\r\n");

        for (int j = 0; j < indent; j++) {

          writer.write(" ");

        }

      }

    }else{

      writer.write(currentChar);

      if(currentChar=='{'){

        writer.write("\r\n");

        indent+=5;

        for(int j=0;j<indent;j++){

          writer.write(" ");

        }

}else if(currentChar==';'){

 //check whether is the end of the method

        if((begin+1)<content.length()&&content.charAt(begin+1)!='}'){

          writer.write("\r\n");

          for (int j = 0; j < indent; j++) {

            writer.write(" ");

          }

        }

      }else {///nothing to do}

    }

    indentContent(writer,content,begin+1,indent);//recursively evaluate next char

 }

}

list 2.2 IndentUtil.java(recursive version of indent method)

动态生成XML

       除了之前提到的代码美容外,我的初试方案中的另外一个缺陷是XML文档是静态写入的,考虑到图形化代码生成器的需要,静态方式将无法满足图形化的要求。因此,这里必须实现XML文档的动态生成功能。可以采取SAX或着DOM标准实现XML动态生成,在此我利用JDOM API,因为它是DOM的面向对象版本,比直接使用DOM更加容易。然后利用JDOM的方法将XML JDOM节点转换为标准的DOM节点,通过JAXPTransformer对象实现从DOM节点并利用XSLTJava代码的转换。

                                   Pic 2.3 UML for My Data Model and JDOM Util

数据模型

       这里我将采用如下策略生成数据模型

1.首先根据之前定义的DTD定制数据结构并采取如下方式,DTD中的任何ELEMENT如果其内容是#PCDATA且没有任何属性,则使用String,否则定义对应的Java类。

2.根据DTDELEMENT定义中的通配符,如果是*+则在对应元素的Java类中使用Collection表示其子元素。

3.对于任何属性列表,在Java类定义中使用Map对象表示。

例如对于Property元素,它的定义为<!ELEMENT property (name,exception*)>,

同时还为其定义了属性列

<!ATTLIST property

       type CDATA #REQUIRED

       access (public | protected | private | package) #REQUIRED

       set (yes | no) #REQUIRED

       get (yes | no) #REQUIRED

>

根据我们的规则,其Java类定义如下

package com.xs.xgen.javabean;

import java.util.*;

public class PropertyData {

 private Map attributes = new HashMap();

 private String name;

 private Collection exceptions;

 public PropertyData(String name,Collection exceptions,Map attributes) {

    this.name=name;

    this.exceptions=exceptions;

    this.attributes=attributes;

 }

 public String getName(){

    return name;

 }

 public Map getAttributes(){

    return Collections.unmodifiableMap(attributes);

 }

 public Collection getExceptions(){

    return Collections.unmodifiableCollection(exceptions);

 }

}

list 2.4 PropertyData.java

同理,JavaBean元素和Package元素的定义就十分直观了

package com.xs.xgen.javabean;

import java.util.*;

public class JavaBeanData {

 private String name;

 private PackageData packageData ;

 private Collection implement;

 private Collection propertyData;

 

 public JavaBeanData(String name,PackageData packageData,Collection implement,Collection propertyData) {

    this.name=name;

    this.packageData=packageData;

    this.implement=implement;

    this.propertyData=propertyData;

 }

 public String getName(){ return name; }

 public PackageData getPackageData(){ return packageData;}

 public Collection getImplement(){

    return Collections.unmodifiableCollection(implement);

 }

 public Collection getPropertyData(){

    return Collections.unmodifiableCollection(propertyData);

 }

}

                        list 2.5 JavaBeanData.java

package com.xs.xgen.javabean;

public class PackageData {

 private String name;

 private String description;

 public PackageData(String name){

    this(name,"");

 }

 public PackageData(String name,String description) {

    this.name=name;

    this.description=description;

 }

 public String getName(){

    return name;

 }

 public String getDescription(){

    return description;

 }

}

                        list 2.6 PackageData.java

读者可能注意到这些类定义完全基于DTD文件,而且之前的XSLT也是基于DTD结构的,所以当处理的XML文档结构复杂时一定要定义DTDXML Schema,即便不包含数据验证机制这样的需求,它们也有助于软件的开发。

  

References

[1] Eric M. Burke. Java and XSLT O’Reilly&Associates,Inc. 2001


 

XMLXSLT实现代码生成器(V)完

 

生成JDOM文档

       当我们定义好数据模型后,下一步就是将数据模型转换为JDOM文档结构。这里可以有不同的设计方式:可以为每个Java类定义对应的工具类用于生成JDOMElement;也可以在每个Java类中添加一个方法用于转换;还可以创建JDOMElement类的定制子类,在子类中,构造函数可以将数据对象作为参数传入。不论使用哪种方法,一致性是最重要的目标[1]。实现非常简单,只要根据DTD定义的对象结构,很容易生成JDOMElement对象。

package com.xs.xgen.javabean;

import java.util.*;

import org.jdom.*;

public class JavaBeanJDOM {

 private JavaBeanJDOM(){}

 public static Element produceElement(JavaBeanData javabean){

    Element javabeanElement=new Element("javabean");

    javabeanElement.addContent(new Element("name").setText(javabean.getName()));

javabeanElement.addContent(

PackageJDOM.produceElement(javabean.getPackageData()));

    Iterator implementIt=javabean.getImplement().iterator();

while(implementIt.hasNext()){

javabeanElement.addContent(new Element("implement").setText((String)implementIt.next()));

    }

    Iterator propertyIt = javabean.getPropertyData().iterator();

    while(propertyIt.hasNext()){

javabeanElement.addContent(

PropertyJDOM.produceElement((PropertyData)propertyIt.next()));

    }

    return javabeanElement;

 }

                            list 2.7 JavaBeanJDOM.java

public class PropertyJDOM {

 private PropertyJDOM() {}

 public static Element produceElement(PropertyData propertyData){

    Element propertyElement = new Element("property");

    addPropertyAttributes(propertyElement,propertyData);

propertyElement.addContent(

new Element("name").setText(propertyData.getName()));

    Iterator exceptionIt = propertyData.getExceptions().iterator();

    while(exceptionIt.hasNext()){

propertyElement.addContent(

new Element("exception").setText((String)exceptionIt.next()));

    }

    return propertyElement;

 }

 

 private static void addPropertyAttributes(Element property,PropertyData data){

    property.addAttribute("type",(String)data.getAttributes().get("type"));

    property.addAttribute("access",(String)data.getAttributes().get("access"));

    property.addAttribute("set",(String)data.getAttributes().get("set"));

    property.addAttribute("get",(String)data.getAttributes().get("get"));

 }

}

                        list 2.8 PropertyJDOM.java

public class PackageJDOM {

 private PackageJDOM() {}

 public static Element produceElement(PackageData packageData){

   Element packageElement = new Element("package");

    packageElement.addContent(new Element("name").setText(packageData.getName()));

    if(!("".equals(packageData.getDescription()))){

packageElement.addContent(

new Element("description").setText(packageData.getDescription()));

    }

    return packageElement;

 }

}

                        list 2.9 PackageJDOM.java

转换JDOM到输出

    当动态生成XML文档为JDOM结构后,唯一要做的就是将其作为数据源输入到JAXP的Transformer类实现实际的代码转换工作。因为当前的JAXP版本并不直接支持JDOM的Element,所以需要首先将JDOM转换为标准的DOM,使用JDOM的DOMOutputter类完成这项任务。

Element root=new Element(xgen);

root.addContent(JavaBeanJDOM.produceElement(javabeanData));

org.jdom.Document doc=

new org.jdom.Document(root);

    org.jdom.output.DOMOutputter domOut=new org.jdom.output.DOMOutputter();

org.w3c.dom.Node domNode = domOut.output(doc);

接下来可以使用JAXP的Transformer类完成转换了。

    Transformer transformer=

TransformerFactory.newInstance().newTransformer(new StreamSource(xslFile));

transformer.transform(new DOMSource(domNode),new StreamResult(javaFile));

图形化代码生成器

       由于所有的数据接口设计已经完成,现在只需要使用一些图形设计工具如NetBeanJbuilder就可以完成图形化的要求,这一步相对简单,图形接口的方法只需要生成对应的数据对象,并利用JDOM生成工具类生成动态XML文件,然后调用JAXPAPI就可以完成代码生成的功能。在此就不做介绍了,有兴趣的读者可以自行设计自己的用户界面。但是要注意XSLT文件的读取,因为它是静态的并存储为文件形式,所以要提供XSLT文件的绝对路径。可以使用Jar将类文件以及XSLT文件打包到一个Jar文件,并使用ClassLoader.getSystemResource(String relativePath) 方法获得XSLT文件的绝对路径。

总结

       本文第一部分介绍了如何使用XMLXSLT实现简单的代码生成功能,第二部分讨论了如何优化生成结果并为图形化需求提供动态XML数据生成功能。本文的目的并不是针对JavaBean代码生成(因为一个只是自动生成JavaBean代码的系统是没有多少吸引力,有很多系统都提供这一功能),而是利用XML&XSLT的组合提供一种针对代码生成问题的轻量级解决方案。读者可以考虑JAXB提供的利用XML Schema自动生成Java对象的功能,使用本文的解决方案可以实现完全同样的功能。类似的问题诸如自动生成Java RMI对象,自动生成EJB类,自动生成WebEJB配制文件,为开发中的类自动生成单元测试代码以及为Web Service数据生成XML Schema以及SOAP消息等等,本文的方案都能够发挥作用,而且容易开发,只要提供元数据,就可以通过XSLT将元数据转换为各种想要的格式。

 

References

[1] Eric M. Burke. Java and XSLT O’Reilly&Associates,Inc. 2001

 

posted on 2007-07-13 08:40  Dragon-China  阅读(1336)  评论(0编辑  收藏  举报