zoukankan      html  css  js  c++  java
  • [转]数据库的XML API(一)

    来源:互联网 酷勤网整理

         数据库和XML提供了数据存储的完整功能。数据库保存数据用于高效的数据查询,而XML则提供了一种不同应用间信息交换的简单途径。为了利用XML的优点,我们需要将数据库表转化为XML文档。然后我们便可以使用指定的XML工具对这些文档进行其它处理。例如,XML文档可通过XSLT样式表转化为HTML页显示,或通过如XQL这样基于XML的查询语言进行检索,或作为一种数据交换格式,等等。然而,通常将一个数据库转化为XML文档代价不菲,要包括开始时数据转化的花费及以后数据源同步的花费。

         为了能处理XML文档,大多数XML工具使用SAX与DOM编程接口。本文中,我们将看到一种数据库通用编程接口的实现方法,它使得XML工具能象处理XML文档一样处理数据库。通过这种方法,我们可以避免对数据库的XML物理转化。

     

          我们会看到一种用于数据库的SAX编程接口实现,它可通过任何JDBC引擎实现对数据库的操作。然后,我们会看到一种用于数据库的DOM编程接口实现,它是通过SAX编程接口间接实现的。为了演示这种用于数据库的SAX编程接口,我们会看到将其与XT(一种XSLT处理器)的集成。我们同样会看到有关这种集成一个范例,它演示了通过将XSLT样式表如何直接作用于数据库来建立一个HTML页面,及如何将一个数据库转化为一个XML文档。最后,我们会看到如何将用于数据库的DOM编程接口与一个XQL处理器相结合。

        本文中,作者利用已有的工具而不是建立一个新的工具来阐明用于数据库的SAX及DOM应用,并显示如何支持众多的XML工具对数据库进行操作。所有本文中提及的XML工具都是免费的(自由软件或非商业用途免费),当然,即使如此,你仍然应该好好看一下有关版权的说明。

     ·   SAX与DOM编程接口的概况

          SAX是一种基于事件的XML编程接口。通过它,SAX解析器可搜索一个XML文档,并告诉应用程序如某元素的开始与结束等事件。由于解析器是通过查看XML文档的不同部分来产生事件的,因此不需要建立任何内部的结构。这大大减少了对系统资源的需求,并且对那些较大的XML文档的解析非常合适。对于那些以接收数据流形式处理的XML文档,基于事件的XML编程接口是唯一选择。

          另一方面,DOM编程接口采用的是一种树型结构。元素之间具有亲子关系,通过DOM编程接口,解析器基于XML文档建立一个内部结构,从而使应用可以通过树型模式对其进行操作。DOM允许一个应用随意访问树型结构文档,代价是增加了内存的负荷。

         · 面向数据库XML编程接口:基本内容

        由于数据库具有高度规范的数据存储结构,因此我们可以将其映射为以数据为中心的XML文档。例如,我们可以通过如下的DTD范例转化一个数据库为XML文档:

    <!ELEMENT table rows*>
    <!ELEMENT rows (column1, column2, ...)>
    <!ELEMENT column1 #PCDATA>
    <!ELEMENT column2 #PCDATA>
    ....
          换句话说,通过一个XML数据库编程接口,我们可以使数据库看起来像一个XML文档:即使用API将数据库封装为一个虚拟的XML文档。这里我们使用了面向对象设计的基本概念:即我们提供的是一个接口,而不是方法的实现。从应用的角度,使用这种XML数据库编程接口的工具并不关心它们处理的实际是XML文档或是一个数据库表。

        · 面向数据库的SAX编程接口实现

       为了实现数据库用的SAX编程接口,我们需要实现一个基于JDBC的解析器,遍历数据源的每一行与列,并产生适当的SAX事件。SAX规范提供了org.xml.sax.InputSource类,它可以将一个数据源以一个URL或一个数据字节流的方式引用。我们可以使用JDBCInputSource,它扩展了org.xml.sax.InputSource类,以下是JDBCInputSource的详细内容:

    // JDBCInputSource.java
    package dbxml.sax;
    import java.sql.*;
    import org.xml.sax.InputSource;
    public class JDBCInputSource extends InputSource {
    private String _connectionURL;
    private String _userName;
    private String _passwd;
    private String _tableName;
    public JDBCInputSource(String connectionURL, String userName,
    String passwd, String tableName) {
    super(connectionURL);
    _connectionURL = connectionURL;
    _userName = userName;
    _passwd = passwd;
    _tableName = tableName;
    }
    public String getTableName() {
    return _tableName;
    }
    public Connection getConnection() throws SQLException {
    return DriverManager.getConnection(_connectionURL, _userName, _passwd);
    }
    }

          在上述的代码中,构造函数使用了数据库连接所需的信息及将被解析的数据库表名。方法getConnection()连接数据库并返回一个连接对象。下一步,我们需要通过JDBCInputSource实现SAX解析器,并遍历数据库表的行与列,产生SAX事件。为了简化代码,我们创建了一个抽象的ParserBase类,它实现了org.xml.sax.Parser类并负责管理不同的句柄。然后我们建立一个基于JDBC的SAX解析器JDBCSAXParser,它扩展了ParserBase类:

    (To view the code for ParserBase.java, click here.)
    // JDBCSAXParser.java
    package dbxml.sax;
    import java.io.IOException;
    import java.sql.*;
    import org.xml.sax.*;
    import org.xml.sax.helpers.AttributeListImpl;
    public class JDBCSAXParser extends ParserBase {
    private static final AttributeList _stockEmptyAttributeList = new AttributeListImpl();
    //------------------------------------------------------------------
    // Methods from the Parser interface
    //------------------------------------------------------------------
    public void parse (InputSource source) throws SAXException, IOException {
    if (! (source instanceof JDBCInputSource)) {
         throw new SAXException("JDBCSAXParser can work only with source " + "of JDBCInputSource type");
    }
          parse((JDBCInputSource)source);
    }

    public void parse (String systemId) throws SAXException, IOException {
       throw new SAXException("JDBCSAXParser needs more information to " + "connect to database");
    }

    //------------------------------------------------------------------
    // Additional methods
    //------------------------------------------------------------------
    public void parse(JDBCInputSource source)
    throws SAXException, IOException {
    try {
    Connection connection = source.getConnection();
    if (connection == null) {
    throw new SAXException("Could not establish connection with " + "database");
    }

    String sqlQuery = getSelectorSQLStatement(source.getTableName());
    PreparedStatement pstmt = connection.prepareStatement(sqlQuery);

    ResultSet rs = pstmt.executeQuery();
    parse(rs, source.getTableName());
    rs.close();

    connection.close();
    } catch (SQLException ex) {
    throw new SAXException(ex);
    }
    }

    public void parse(ResultSet rs, String tableName)
    throws SAXException, SQLException, IOException {
    if (_documentHandler == null) {
    return; // nobody is interested in me, no need to sweat!
    }

    ResultSetMetaData rsmd = rs.getMetaData();
    int numCols = rsmd.getColumnCount();

    String tableMarker = getTableMarker(tableName);
    String rowMarker = getRowMarker();

    _documentHandler.startDocument();
    _documentHandler.startElement(tableMarker, _stockEmptyAttributeList);
    while(rs.next()) {
    _documentHandler.startElement(rowMarker, _stockEmptyAttributeList);
    for (int i = 1; i <= numCols; i++) {
    generateSAXEventForColumn(rsmd, rs, i);
    }
    _documentHandler.endElement(rowMarker);
    }
    _documentHandler.endElement(tableMarker);
    _documentHandler.endDocument();
    }

    public void parse(String connectionURL, String userName, String passwd, String tableName) throws SAXException, IOException {
    parse(new JDBCInputSource(connectionURL, userName, passwd, tableName));
    }

    //------------------------------------------------------------------
    // Protected methods that derived classes could override to
    // customize the parsing.
    //------------------------------------------------------------------
    protected void generateSAXEventForColumn(ResultSetMetaData rsmd, ResultSet rs, int columnIndex)
    throws SAXException, SQLException {
    String columnvalue = rs.getString(columnIndex);
    if (columnvalue == null) {
    return;
    }
    String columnMarker
    = getColumnMarker(rsmd.getColumnLabel(columnIndex));
    char[] columnvalueChars = columnvalue.toCharArray();
    _documentHandler.startElement(columnMarker, _stockEmptyAttributeList);
    _documentHandler.characters(columnvalueChars, 0, columnvalueChars.length);
    _documentHandler.endElement(columnMarker);
    }

    protected String getTableMarker(String tableName) {
    return tableName;
    }
    protected String getRowMarker() {
    return "row";
    }
    protected String getColumnMarker(String columnName) {
    return columnName;
    }
    protected String getSelectorSQLStatement(String tableName) {
    return "select * from " + tableName;
    }
    }

    (未完待续)

  • 相关阅读:
    'yiiaseInvalidRouteException' with message 'Unable to resolve the request "site/error".'
    yii2:不使用composer安装yii2-jui的方法
    Oracle cmd乱码
    oracle 11g安装过程中问题:移动binoralbac11.dll 到binoralbac11.dll.dbl出错
    yii2打印数据属性(字段名)/数据
    在xampp集成环境下使用 php 连接oracle
    phalcon: 项目地址/P(.*), 项目地址/Pbaidu 与 路由
    PHP返回32位与16位的md5加密值
    PHP调用webservice接口
    java:日期格式化
  • 原文地址:https://www.cnblogs.com/monica/p/1785747.html
Copyright © 2011-2022 走看看