配置XMLBeans

配置XMLBeans

时间:2005-03-10
作者:Hetal Shah
浏览次数: 961
本文关键字:配置XMLBeans
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章
XMLBeans 1.0.3最强大的功能之一是可通过提供配置文件定制代码生成。在灵活性、可重用性、简化代码和维护方面,XMLBeans的功能带来了许多益处。因为任何企业应用程序相当大部分的成本都在于维护方面,所以从长远来看,XMLBeans的配置功能能够代表对成本和时间的节省。
  本文通过一系列的示例对这些功能进行了说明。我们假设您已熟悉XMLBeans。对于入门者,参见下面列出的介绍XMLBeans的文章。本文中提及的示例代码和其他文件可以下载。示例已在Apache XMLBeans 1.0.3、Java 1.4.2_02和Microsoft Windows 2000上通过测试。

  运行XMLBeans编译器时,可以指定可选配置文件来修正XMLBeans生成器的行为。默认情况下,该配置文件应当具有.xsdconfig扩展名。配置文件的结构遵循以下模式:
<?xml version="1.0" encoding="UTF-8"?>
<xb:config
  xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config">
...
</xb:config>
  正如您所看到的,根config元素必须位于http://xml.apache.org/xmlbeans/2004/02/xbean/config名称空间中。真正的配置功能必须位于config元素之内,可按任何次序排放。
  有了模式文件(比如someSchema.xsd)和配置文件(比如someConfig.xsdconfig)之后,下一步即是生成一系列代表该模式的XMLBeans类。以下为命令行用法示例:
scomp -out output_XmlBeans.jar someSchema.xsd someConfig.xsdconfig
  注意配置文件只是简单添加到scomp的附加参数。这将确保生成器使用您所指定的任何扩展功能。以下部分对这些功能依次进行了检查。

向已生成的类名添加前缀或后缀
  XMLBeans提供了简单配置功能,用于从特定的名称空间中为模式类型创建的XMLBeans类名添加前缀名及后缀名。该功能对于将从特定名称空间中生成的模式类型的XMLBeans类同其他XMLBeans和在工程中使用的JavaBeans区别开来很有用。
  这只是最简单的功能。我们在介绍模式示例时将还会使用这一部分。清单1显示了贯穿本文使用的localInfo.xsd模式。它描述了包含一个地点(基于邮编)天气信息的XML文档。

清单1. localInfo.xsd
<xsd:schema
targetNamespace="http://www.localInfo.com/LI"
...
xmlns:ns1 = "http://www.helloWeather.com/weather"
>

<xsd:import
namespace="http://www.helloWeather.com/weather"
schemaLocation="weather.xsd"/>

<xsd:element name="localInfo">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element ref="ns1:localWeather"/>
   </xsd:sequence>
  <xsd:attribute ref="Zipcode"/>
 </xsd:complexType>
 </xsd:element>

 <xsd:attribute name="Zipcode" type="xsd:string"/>

</xsd:schema>
  该localInfo.xsd 模式导入 weather.xsd,如清单2所示。

清单 2. weather.xsd
<xsd:schema targetNamespace=
"http://www.helloWeather.com/weather"
....
>

<xsd:element name="localWeather">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element ref="Temperature"/>
    <xsd:element ref="Humidity" />
    <xsd:element ref="Visibility" />
    <xsd:element ref="Datetime" />
    <xsd:element ref="image"
    minOccurs="1" maxOccurs="1"/>
   </xsd:sequence>
  <xsd:attribute ref="Zipcode"/>
 </xsd:complexType>
 </xsd:element>

<xsd:element name="Temperature"
     type="xsd:float"/>
<xsd:element name="Humidity"
     type="xsd:float"/>
<xsd:element name="Visibility"
     type="xsd:float"/>
<xsd:element name="Datetime"
     type="xsd:dateTime"/>
<xsd:element name="image"
     type="imageType"/>
<xsd:attribute name="Zipcode"
         type="xsd:string"/>

<xsd:complexType name="imageType">
 <xsd:simpleContent>
  <xsd:extension base="xsd:base64Binary" >
   <xsd:attribute name="type" use="optional"
       type="xsd:string"/>
  </xsd:extension>
 </xsd:simpleContent>
</xsd:complexType>
  最后,清单3显示了一个简单完整的配置文件(localInfo.xsdconfig),它说明了XMLBeans前缀、后缀功能的用法。

清单3:localInfo.xsdconfig:前缀和后缀的配置
<xb:config xmlns:xb=
"http://xml.apache.org/xmlbeans/2004/02/xbean/config"
>
 <xb:namespace uri="##any">
  <xb:suffix>XmlBean</xb:suffix>
  <xb:prefix>pre</xb:prefix>
 </xb:namespace>
</xb:config>
  prefix和suffix元素分别指定了从名称空间中为模式类型创建的XMLBeans类名的前缀和后缀,其中名称空间由namespace元素中的uri属性值定义。在以上localInfo.xsdconfig列表中,我们希望不论模式类型代表什么名称空间,都为所有从XML模式创建的XMLBeans类名添加前缀“XmlBean”。为此示例,我们不使用前缀功能。
下一步是创建一个代表localInfo.xsd的一组XMLBeans类。在从示例存档提取文件的工作目录中提示处,输入下列行:
scomp -out localinfo_XmlBeans.jar localInfo.xsd localInfo.xsdconfig
  使用配置文件的结果是,生成的XMLBean类将具有适当的后缀。例如,为Zipcode属性生成的XMLBean将被称作ZipcodeAttributeXmlBean.java,而不是原来默认情况下的ZipcodeAttribute。

XML到Java名映射和名称空间URI到包名映射
  XMLBeans具有将XML名映射为Java名称和将名称空间URI映射为Java包名称的配置能力。这允许开发人员在XML名称或名称空间URI改变的情况下,避免重写Java代码,从而使其基于XMLBeans的应用程序更具灵活性。
  作为一个示例,考虑以下配置文件,它为创建模式时我们所使用的每一个名称空间都分配了一个包名称:
<xb:config
 xmlns:xb=
 "http://xml.apache.org/xmlbeans/2004/02/xbean/config"
xmlns:NS1="http://www.helloWeather.com/weather">

...

<xb:namespace uri="http://www.localInfo.com/LI">
  <xb:package>com.localInfo</xb:package>
</xb:namespace>

<xb:namespace uri="http://www.helloWeather.com/weather">
  <xb:package>com.weather</xb:package>
</xb:namespace>

<xb:qname name="NS1:image" javaname="MapXmlBean"/>
...
</xb:config>
  记得要为使用的名称空间声明前缀来使元素成为配置文件中的一部分。这里我们已经为config元素中的http://www.helloWeather.com/weather名称空间声明了前缀NS1。
从该示例可以看出,namespace和package元素用于将名称空间URI映射为应当生成的Java包名称。下面的namespace元素将http://www.localInfo.com/LI名称空间映射为包名com.localInfo。
<xb:namespace uri="http://www.localInfo.com/LI">
  <xb:package>com.localInfo</xb:package>
</xb:namespace>
  这样使用的结果是,为模式类型生成的、属于http://www.localInfo.com/LI名称空间的XMLBean类的包名称是com.localInfo,而不是原来默认情况下的com.localInfo.li。
qname元素用于将模式类型名映射为生成的相应的XMLBeans Java类名称。Qname元素的Name属性对于模式类型是限定的名称,同时javaname属性值代表了相应的生成的XMLBeans类名。
  在weather.xsd中声明的image元素代表了一个位置的映射。在前面的示例中我们使用qname扩展名来将image元素映射为名为MapXmlBean的Java类,使image元素的Java名更加直观。注意:qname比namespace具有更高优先权,所以Java名称指定为MapXmlBean而不只是Map,这样就能与其他XMLBeans类名具有一致性。

接口扩展
  接口扩展功能对于用和它代表的模式类型的结构和属性无关的方法来扩展XMLBean很有用。例如,具有天气状况细节的XML文档中的温度数据用华氏温度表示,但是一些使用相应XMLBeans的客户端应用程序需要摄氏温度表示的数据来作进一步处理。使用接口扩展功能,能将一个转换函数float getTemperatureInCelsius()添加到XMLBean中,它将华氏温度数据转换为摄氏温度。

这里是使用extension元素来完成此功能的配置文件的代码摘录:
<xb:extension for=
"com.weather.LocalWeatherDocumentXmlBean"
>
 <xb:interface
     name="com.extension.weatherExtension">
  <xb:staticHandler>
  com.extension.weatherExtensionHandler
  </xb:staticHandler>
 </xb:interface>
</xb:extension>
  for属性能够接收按空间划分的XMLBeans Java接口列表,或者使用“*”来包含扩展中的所有接口。这种做法的结果是,生成的XMLBeans接口LocalWeatherDocumentXmlBean将扩展指定的接口,在本例中将扩展为com.extension.weatherExtension。该例中,我们为接口声明了两种方法:
public interface weatherExtension {
  float getTemperatureInCelsius();
  float getVisibilityInKilometers();
}
  对于com.extension.weatherExtension接口的实现方法将自动在相应的XMLBeans实现类LocalWeatherDocumentXmlBeanImpl中生成。这些实现方法将委托给特定的扩展处理程序的com.extension.weatherExtensionHandler方法。
  扩展处理程序类com.extension.weatherExtensionHandler必须包括一个与接口方法有相同名称的public static方法,但是第一个参数必须为XmlObject类型,接下来是接口方法的参数,如下:
public static float getTemperatureInCelsius
(XmlObject xo) {

.....
}

public static float getVisibilityInKilometers
(XmlObject xo) {

.....
}
   每次LocalWeatherDocumentXmlBean实例的扩展方法被调用时,都将调用以上两个方法。
  因为XMLBeans根据模式生成文档类,所以这些文档类必须在其他任何依靠它们的扩展类编译前进行构建。由于这种循环的依赖性,建构所有部分需要一点技巧。
通过接口扩展功能构建XMLBeans分为三步。
  1. 将对extension元素的XML注释置于localInfo.xsdconfig文件中。然后,在从示例存档提取文件的工作目录的提示处,输入下列行:
    scomp -out localinfo_XmlBeans.jar localInfo.xsd localInfo.xsdconfi
  2. 使用localinfo_XmlBeans.jar和xbean.jar编译扩展接口和处理程序类。
    SET CLASSPATH=%CLASSPATH%;localinfo_XmlBeans.jar;.;c:/xmlbeans-1.0.3/lib/xbean.jar
           javac -d . weatherExtension.java
           javac -d . weatherExtensionHandler.java
  3. 删除localInfo.xsdconfig文件中围绕extension元素的XML注释。然后通过localInfo.xsd文件和localInfo.xsdconfig文件再次运行scomp,确保已编译的扩展类在classpath上。
    scomp -out localinfo_XmlBeans.jar localInfo.xsd localInfo.xsdconfig

  哇!我们已经准备好了编译并运行包含在示例存档中的基于XMLBeans的客户端应用程序extensionClient.java。

javac extensionClient.java
java extensionClient localInfo_68154.xml
  通过使用接口扩展功能,我们已经将附加逻辑从客户端应用程序移至XMLBean Java代码上。现在的代码已集中化并可重用。同时,XMLBean的客户端应用程序变得更简洁精练。

PrePost扩展
  使用prepost扩展功能时,在指定的XMLBeans的所有setter方法开始和结束时将生成对扩展处理程序的pre和post调用。
  我们说我们不希望我们的基于XMLBeans的客户端应用程序对由image元素的内容代表的映射进行修改。为了实行该约束,将下列extension元素添加到localInfo.xsdconfig文件中:
<xb:extension for="
com.weather.LocalWeatherDocumentXmlBean
">
 <xb:prePostSet>
  <xb:staticHandler>
    com.extension.MapPrePostSetHandler
  </xb:staticHandler>
 </xb:prePostSet>
</xb:extension>
  extension元素的for属性指定了按空间划分的XMLBeans的列表,其中setter方法按照下面LocalWeatherDocumentXmlBean类所展示的那样调用preSet()方法和postSet()方法:
/**
 * Sets the "image" element
 */
public void setMapXmlBean
        (com.weather.ImageTypeXmlBean mapXmlBean)
{
 synchronized (monitor())
 {
  check_orphaned();
  if ( com.extension.MapPrePostSetHandler.preSet
            (1, this, MAPXMLBEAN, false, -1)
      )
      {

       .... Code to set ImageTypeXmlBean instance
      }
  com.extension.MapPrePostSetHandler.postSet
              (1, this, MAPXMLBEAN, false, -1);
 }
}

/**
 * Appends and returns a new empty "image" element
 */
public com.weather.ImageTypeXmlBean
       addNewMapXmlBean()
{
 synchronized (monitor())
 {
  check_orphaned();
  com.weather.ImageTypeXmlBean target = null;
  if ( com.extension.MapPrePostSetHandler.preSet
            (2, this, MAPXMLBEAN, false, -1)
      )
      {
       ...
       Code to create and return an empty instance
       of ImageTypeXmlBean
       ...
      }
  com.extension.MapPrePostSetHandler.postSet
       (2, this, MAPXMLBEAN, false, -1);
  return target;
 }
}
  以上代码是使用PrePost扩展将生成什么结果的一个示例。注意在set方法和append方法中都调用了pre和post方法。
  以下是一些来自MapPrePostSetHandler.java的代码,说明了怎样实现阻止客户端应用程序修改image元素内容的preSet()和postSet()方法。
 public static boolean preSet (int operationType,
                XmlObject xo, QName propertyName,
                boolean isAttr, int indexOfItem){

  javax.xml.namespace.QName imageQName =
  new javax.xml.namespace.QName
  ("http://www.helloWeather.com/weather","image");

  if( (xo instanceof LocalWeather)
      && ( propertyName.equals(imageQName) ) )
   {
     return false;
   }

   return true;
 }
  ...

  public static void postSet(int operationType,
              XmlObject xo, QName propertyName,
              boolean isAttr, int indexOfItem)
   {}
  preSet()方法通知扩展处理器将对XMLBeans对象执行一些设置、插入或删除操作。这是扩展处理程序类必须阻止那个操作的最后机会。

  preSet()方法返回一个boolean值。如果返回的值是:
  • true,则执行要执行的操作。
  • false,则跳过要执行的操作。

  如果XMLBeans对象是LocalWeather的一个实例,并且要修改的属性是属于http://www.helloWeather.com/weather名称空间的image元素,我们的MapPrePostSetHandler的preSet()方法将返回false;否则,返回true。XMLBeans并不提供指定生成的XMLBeans类是否应当具有add、remove或set方法的功能。如前所述,我们能够在运行期间通过PrePost扩展功能来控制这些方法的流。
  操作完成或跳过操作之后,XMLBeans类调用postSet()方法。preSet()方法和postSet()方法的参数如下所示:

int operationType

Type of the operation. Possible values are org.apache.xmlbeans.impl.config.PrePostExtension.OPERATION_SET for set operations, org.apache.xmlbeans.impl.config.PrePostExtension.OPERATION_INSERT for add operations, and org.apache.xmlbeans.impl.config.PrePostExtension.OPERATION_REMOVE for remove operations.

XmlObject xo

Instance of XmlObject on which the operation is called.

QName propertyName

Qualified name of the element or attribute to be operated on.

boolean isAttr

true if the property is an attribute, otherwise false.

int indexOfItem

Index of the item to be set, when an element identified by propertyName allows several values, that is, declares maxOccurs > 1.

  构建既有interface扩展功能又有PrePost扩展功能的XMLBeans需要一点技巧,在示例存档的build.txt文件中对这些技巧进行了说明。存档文件中提供了说明PrePost扩展功能有效性的、基于XMLBeans的客户端应用程序prePostClient.java,存档文件可从以下“附加阅读”一节下载得到。

结束语
  XMLBeans的配置功能带来了许多益处,如减少代码维护成本的同时增加代码的灵活性。尽管prefix/suffix扩展在这些功能中作用或许最小,包命名功能却至关重要。接口扩展功能是把附加功能引入XMLBeans框架的好方法,同时PrePost扩展提供了一个穷人的AOP功能:对允许您执行的操作(比如根据某些条件有选择地执行一些操作)进行了包装。

附加阅读
· sample.zip——本文的示例模式、Java代码及XML文件。
· XMLBeans——Apache XMLBeans分发。
· 使用XMLBeans的XML-Java数据绑定——对XMLBeans的介绍。

原文出处
http://dev2dev.bea.com/technologies/xmlbeans/articles/Configuring_XMLBeans.jsp

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页