hengheng123456789

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  297 Posts :: 68 Stories :: 144 Comments :: 0 Trackbacks

编写映射文件

映射文件是一个特殊的XML文件,用户在其中指定XML元素、属性(attributes)以及PCDATA如何映射到数据库的表与列。清单A就是这个XML示例的映射文件,清单B是 数据库的一个SQL架构。在清单A中,Options元素包含系统特有的一些参数。在这例子中,你要设置相应的格式,以实现DATE类型的数据库字段与 XML数据的相互转换。注意,Pattern属性必须遵循java.text.SimpleDateFormat模式规范。

清单A:

Listing A
<?xml version='1.0' ?>

<XMLToDBMS Version="2.0" xmlns="http://www.xmlmiddleware.org/xmldbms/v2">

<Options>

<SimpleDateFormat Pattern="yyyy-MM-dd" DefaultForTypes="DATE" />

</Options>

<Databases>

<Database Name="Default">

<Catalog>

<Schema>

<Table Name="users">

<Column Name="user_id" DataType="VARCHAR" Length="24" Nullable="No"/>

<Column Name="company" DataType="VARCHAR" Length="255" Nullable="No"/>

<PrimaryKeyKeyGenerator="UID">

<UseColumn Name="user_id"/>

</PrimaryKey>

</Table>

<Table Name="orders">

<Column Name="order_id" DataType="VARCHAR" Length="24" Nullable="No"/>

<Column Name="user_id" DataType="VARCHAR" Length="24" Nullable="No"/>

<Column Name="posted_at" DataType="DATE" Nullable="No"/>

<Column Name="type" DataType="INTEGER" Nullable="Yes"/>

<ForeignKey Name="order_to_user_FK">

<UseTable Name="users" />

<UseUniqueKey Name="PrimaryKey" />

<UseColumn Name="user_id"/>

</ForeignKey>

<PrimaryKeyKeyGenerator="UID">

<UseColumn Name="order_id"/>

</PrimaryKey>

</Table>

<Table Name="cargos">

<Column Name="cargo_id" DataType="VARCHAR" Length="24" Nullable="No"/>

<Column Name="order_id" DataType="VARCHAR" Length="24" Nullable="No"/>

<Column Name="title" DataType="VARCHAR" Length="255" Nullable="Yes"/>

<Column Name="code" DataType="VARCHAR" Length="255" Nullable="Yes"/>

<Column Name="quantity" DataType="INTEGER" Nullable="Yes"/>

<Column Name="weight" DataType="INTEGER" Nullable="Yes"/>

<Column Name="danger" DataType="VARCHAR" Length="255" Nullable="Yes"/>

<PrimaryKeyKeyGenerator="UID">

<UseColumn Name="cargo_id"/>

</PrimaryKey>

<ForeignKey Name="cargo_to_order_FK">

<UseTable Name="orders" />

<UseUniqueKey Name="PrimaryKey" />

<UseColumn Name="order_id"/>

</ForeignKey>

</Table>

</Schema>

</Catalog>

</Database>

</Databases>

<Maps>

<ClassMap>

<ElementType Name="order"/>

<ToClassTable Name="orders"/>

<PropertyMap>

<ElementType Name="order_id"/>

<ToColumn Name="order_id"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="user_id"/>

<ToColumn Name="user_id"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="posted_at"/>

<ToColumn Name="posted_at"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="type"/>

<ToColumn Name="type"/>

</PropertyMap>

<RelatedClassKeyInParentTable="Unique">

<ElementType Name="cargo"/>

<UseUniqueKey Name="PrimaryKey"/>

<UseForeignKey Name="cargo_to_order_FK"/>

</RelatedClass>

</ClassMap>

<ClassMap>

<ElementType Name="cargo"/>

<ToClassTable Name="cargos"/>

<PropertyMap>

<ElementType Name="cargo_id"/>

<ToColumn Name="cargo_id"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="order_id"/>

<ToColumn Name="order_id"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="title"/>

<ToColumn Name="title"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="code"/>

<ToColumn Name="code"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="quantity"/>

<ToColumn Name="quantity"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="weight"/>

<ToColumn Name="weight"/>

</PropertyMap>

<PropertyMap>

<ElementType Name="danger"/>

<ToColumn Name="danger"/>

</PropertyMap>

</ClassMap>

</Maps>

</XMLToDBMS>
清单B:
Listing B
CREATE TABLE XMLDBMSKey (
HighKeyint(11)
);
CREATE TABLE orders (
order_idvarchar(24) DEFAULT '' NOT NULL,
user_idvarchar(24) DEFAULT '' NOT NULL,
posted_atdate,
type integer,
PRIMARY KEY (order_id)
);
CREATE TABLE cargos (
cargo_idvarchar(24) DEFAULT '' NOT NULL,
order_idvarchar(24) DEFAULT '' NOT NULL,
title varchar(255),
code varchar(255),
quantity integer,
weight integer,
danger varchar(255),
PRIMARY KEY (cargo_id)
);


清单A的Databases元素包含数据库的一个关系架构。该构架确保XML-DBMS能正确地映射数据并编译映射文件(如果要在多个映射文件中使用相同的数据库架构,最好的办法就是在每个文件中将架构作为一个XML外部实体来包容,不必每次都进行重写)。

数据库名称“Default”意味着数据库必须在JDBC连接URL中显式地指定。必须在每个表中提供主键信息,而且每个键都必须存在于数据库中。否则,编译器可能报告一个映射异常。

在KeyGenerator中,你需要提供主键生成器的名称,同时必须用一个独立的Java类来实现这个生成器。KeyGenerator是Java接口的一个实现,每次执行一个INSERT操作时,它都会生成一个惟一的键值。也可使用一个简单的、现成的生成器。

图B的XMLDBMSKey表包含了由KeyGenerator使用的值。UseColumn元素指向一个充当主键的元素,并告诉程序在哪里写生成 的键值。除非Name属性明确指定了一个名称,否则主键会隐式地采用PrimaryKey这一默认名称。主键可能同时使用了多列, KeyGenerator的实现必须知道它应该生成多少个键。

清单A的ForeignKey元素用于描述元素类之间的主键–外键关系。

在映射文件中,最重要的一部分就是Maps小节。元素类型及其内容通常被视为一个类,并映射到一个表。这是通过一个ClassMap元素及其子元素 来完成的。子元素包括ElementType,其中含有要映射的元素的名称;以及ToClassTable,它指定元素要映射到哪个表。

PropertyMap元素能控制“简单”(子节点中的PCDATA)元素或属性(attribute)映射——虽然在这个例子中,应用程序映射的 只是元素。RelatedClass元素允许我们在此封装另一个元素类,但那个类必须在另一个ClassMap元素中得到定义。

映射文档编译成XMLDBMap Java对象,最终的结果会传给DBMSToDOM、DOMToDBMS或者DBMSDelete对象。这些特殊对象负责与选择、插入、更新或删除数据有关的全部工作。


编写过滤器和动作文件

过滤器文档由一系列过滤器构成,这些过滤器应用于数据库中的值。这样一来,过滤器就能过滤由SELECT操作检索的行或者由DELETE操作删除的 行。过滤器语言位于映射语言的顶端。换言之,过滤器文档允许你指定数据的检索条件,而映射语言提供结构化信息(也就是联接–join)。你可认为映射语言 和过滤器语言合并在一起,共同为数据库提供了一套简单的查询语言,它确保结果以XML的形式返回。过滤器文档要编译成FilterSet Java对象,最终的对象会传给DBMSToDOM或者DBMSDelete对象。

动作文档由一系列动作构成,这些动作要应用于XML文档中的值。你需要为作为类来映射的元素类型指定相应的动作。这些动作会转换为对行的插入、更新 及删除操作。在一个动作文档中,如果已经规定特定的行需要插入或更新,就不能再规定那些行需要删除;反之亦然。如果一个动作文档规定某些行需要插入或更 新,就会由DOMToDBMS对象来使用那些文档。相反,如果规定某些行需要删除,则会由DBMSDelete对象来使用。

Listing C

<?xmlversion='1.0' ?>
<Actions Version="2.0" xmlns="http://www.xmlmiddleware.org/xmldbms/actions/v2">
<DefaultAction>
<None />
</DefaultAction>
<Action>
<ElementType Name="order" />
<UpdateOrInsert />
</Action>
<Action>
<ElementType Name="cargo" />
<UpdateOrInsert />
</Action>
</Actions>

清单C演示了插入/更新动作。这段代码会使用一个已知的主键(如果存在的话)来更新一个行,或者生成一个新的主键(如果不存在的话)。实际上,你需要为两个类(order和cargo)插入元素,因为cargo元素嵌套在order元素中。

Listing D

<?xmlversion='1.0' ?>
<FilterSet Version="2.0" xmlns="http://www.xmlmiddleware.org/xmldbms/filters/v2">
<Options>
<Wrapper Name="orders" />
</Options>
<Filters>
<Filter>
<RootFilter>
<Table Name="orders" />
<Where Condition=" user_id = 'UID745632' "/>
</RootFilter>
</Filter>
</Filters>
</FilterSet>

选择或删除数据时,需要使用包含在清单D中的过滤器文件。Options元素包含一个特殊的Wrapper元素,它用于包装查询结果。如果会从数据 库中检索多个元素,就需要使用Wrapper元素。在这种情况下,生成的是含有多个根元素的XML结构,现行的许多标准都不支持它。

RootFilterelements用于指定从根表检索到的值。


编写Java代码

现在,我们已准备好编写自己的应用程序,它将在一个关系数据库中存储和检索DOM文档。清单E包含了示范性的Java代码,它有必要进一步说明。

Listing E

package test.xmldbms;
importorg.xmlmiddleware.db.*;
import org.xmlmiddleware.utils.XMLMiddlewareException;
importorg.xmlmiddleware.xmldbms.*;
importorg.xmlmiddleware.xmldbms.tools.*;
importorg.xmlmiddleware.xmldbms.actions.*;
importorg.xmlmiddleware.xmldbms.datahandlers.*;
importorg.xmlmiddleware.xmldbms.filters.*;
importorg.xmlmiddleware.xmldbms.keygenerators.*;
importorg.xmlmiddleware.xmldbms.maps.*;
importorg.xmlmiddleware.xmlutils.*;
importorg.xml.sax.*;
import org.w3c.dom.*;
importjava.io.*;
importjava.util.*;
public class XMLToDBMSAndViceVersa
{
// Service objects
private DOMToDBMSdomToDBMS = null;
private DBMSToDOMdbmsToDOM = null;
private DBMSDeletedbmsDelete = null;
// Credentials for connecting to database
private static String JDBC_DRIVER = "org.gjt.mm.mysql.Driver";
private static String JDBC_URL = "jdbc:mysql://localhost/dbname";
private static String JDBC_DBNAME = "dbname";
private static String JDBC_USER = "dbuser";
private static String JDBC_PASSWORD = "dbpassword";
// Some file names
private static String mapFilename = "Listing-A.map";
private static String actionFilename = "Listing-C.act";
private static String filterFilename = "Listing-D.act";
// Datahandler class
private static String GENERICHANDLER = "org.xmlmiddleware.xmldbms.datahandlers.GenericHandler";
// Key generation class
private static String KEYGENERATOR = "org.xmlmiddleware.xmldbms.keygenerators.KeyGenerator";
// Parser utils class; XML-DBMS does not yet support JAXP, so such operations as XML parsing and serializing
// needs to be a little customized for each parser. this is the class for supporting Xerces parser.
private static String PARSERUTILSCLASS = "org.xmlmiddleware.xmlutils.external.ParserUtilsXerces";
private static boolean VALIDATING_PARSER = false;
public static void main(String [] args) {
// Tell the JVM to run finalizers on exit. This is necessary to ensure
// that database connections are properly closed.
System.runFinalizersOnExit(true);
// Creating parser utilities
ParserUtilsutils = (ParserUtils)Class.forName(PARSERUTILSCLASS).newInstance();
// Creating a data source and data handler.
DataSourcedataSource = new JDBC1DataSource(JDBC_DRIVER, JDBC_URL);
dataHandler = (DataHandler)Class.forName(GENERICHANDLER).newInstance();
dataHandler.initialize(dataSource, JDBC_USER, JDBC_PASSWORD);
// Compiling and instantiating a Map object
MapCompiler compiler = new MapCompiler(utils.getXMLReader(VALIDATING_PARSER));
XMLDBMSMap map = compiler.compile(new InputSource(new FileReader(mapFilename)));
// Create an object containing information needed to transfer data
TransferInfotransferInfo = new TransferInfo(map);
transferInfo.addDataHandler(JDBC_DBNAME, dataHandler);
// Compiling and instantiating an Action object
ActionCompiler compiler = new ActionCompiler(utils.getXMLReader(VALIDATING_PARSE));
Actions actions = compiler.compile(map, new InputSource(new FileReader(actionFilename)));
// Creating and configuring service object
domToDBMS = new DOMToDBMS();
domToDBMS.setCommitMode(DataHandler.COMMIT_AFTERSTATEMENT);
domToDBMS.stopOnException(true);
domToDBMS.setFilterSetReturned(false);
KeyGeneratorkeyGen = (KeyGenerator)Class.forName(KEYGENERATOR).newInstance();
domToDBMS.addKeyGenerator("UID", keyGen); // Adding used in Listing-A key generator named UID
// Getting our XML document into DOM document
Document doc = utils.openDocument(new InputSource(new StringReader(xmlString)),VALIDATING_PARSER);
// Ooops... and our XML file is already in the database!
domToDBMS.storeDocument(transferInfo, doc, actions);
// Creating FilterSet object for retrieving data
FilterCompiler compiler = new FilterCompiler(utils.getXMLReader(validate));
FilterSetfilterSet = compiler.compile(map, new InputSource(new FileReader(filterFilename)));
// Creating and configuring another service object
dbmsToDOM = new DBMSToDOM(utils);
dbmsToDOM.setDTDInfo(null, null);
Hashtableparams = new Hashtable();
// And now we are getting a DOM document from database
doc = dbmsToDOM.retrieveDocument(transferInfo, filterSet, params, null);
}
}

首先,你必须实例化一个数据源和一个数据处理程序。JDBC1DataSource类是JDBC 2.0 DataSource的一个实现,它用于一个遵循JDBC1标准的驱动程序,而且提供了对连接池的支持。Datahandler是用于对数据库访问进行抽 象的一个接口。你还要指示JVM在退出时运行终结器(finalizers),这是用System.runFinalizersOnExit(true) 来实现的。终结器必须运行,否则无法保证数据库连接正确关闭。ParserUtils是实现了解析器特有方法的一个类的接口。之所以需要它,是因为XML 解析和序列化操作需要针对每一个解析器进行少许定制。

你必须编译和实例化一个Map对象、Actions对象以及FilterSet对象,它们全都会在文档转换过程中使用。为此,你需要使用由 MapCompiler、ActionCompiler和FilterCompiler等对象提供的相应的方法。TransferInfo对象包含在 XML文档和数据库之间传输数据所需的信息。它封装了根据一个特定的映射,在XML文档和数据库之间传输数据所需的映射元数据以及DataHandler 对象。它为每个数据库都包含单独一个XMLDBMSMap对象和一个DataHandler对象。你还必须创建一个KeyGenerator实现对象,以 便在插入新对象时生成主键。键用于联接不同的表(从类表到类表,或者从类表到属性表),还用于从根表(root tables)检索数据。

最后,你可创建一个DOMToDBMS对象,以便将数据从一个DOM树传输到数据库。采取类似的方式,还可创建一个DBMSToDOM对象,以便将关系数据传回DOM。

总结

本文证明使用XML-DBMS来存储XML数据其实并不难。如果你已经建立了一个关系数据库基础结构,或者希望建立一个独立于数据库厂商的基础结 构,就推荐采取这种方式。由于XML-DBMS不要求任何特定的数据库,所以你的数据库只需理解标准SQL,而且有一个JDBC驱动程序(或者具有桥接机 制的一个 ODBC驱动程序)就可以了。如果你的应用程序需要搜索或者合并来自不同类型的数据源的信息,就适合使用这个框架,因为关系数据库架构很容易通过XML DTD和XML架构来建立,另外还有大量工具可将DTD和架构转换成映射文件。另外,还可用它生成由数据驱动的应用程序,比如一个CMS或者CRM系统。 XML-DBMS是从XML到DBMS的中间件产品的一个典范,能有效地整合支持和不支持XML的系统。



posted on 2006-09-04 11:40 哼哼 阅读(813) 评论(1)  编辑  收藏 所属分类: XML

Feedback

# re: 使用Java和XML-DBMS将数据库桥接到XML 2007-12-06 16:46 lynn
您的这篇文章
是您自己总结的么?
看了之后,还是有一些不太明白的地方。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: