|
XML APIs for databases广告 XML APIs for
databases Ramnivas Laddad Most Web applications require the presentation of database-generated information. XML, because of its ability to separate content from presentation, is fast becoming an industry standard for data exchange. Most XML tools work with either the SAX or DOM API. This article presents a way to blend the power of a database with the features of XML. It also provides a simple, pure Java implementation of XML APIs for databases that works with any JDBC data source. With this approach, XML tools can treat a database as a virtual XML document. Databases and XML offer complementary functionality for storing data. Databases store data for efficient retrieval, whereas XML offers an easy information exchange that enables interoperability between applications. To take advantage of XML's features we can convert database tables into XML documents. We can then use XML tools with such documents for further processing. For example, XML documents can be presented as HTML pages with XSLT stylesheets, can be searched with XML-based query languages such as XQL, can be used as a data-exchange format, and so on. However, converting a database into an XML document is an expensive approach, one that requires not only the initial cost of conversion but also the subsequent costs of synchronizing both information sources. For processing XML documents, most XML tools work with the SAX or DOM API. In this article, we'll look at a way to implement the same APIs directly over a database, enabling XML tools to treat databases as if they were XML documents. That way, we can obviate the need of converting a database. We'll see an implementation of the SAX API for Databases that should work with any database with a JDBC driver. Next, we'll examine an implementation of the DOM API for Databases that uses the SAX API internally. To demonstrate the SAX API for Databases, we'll look at its integration with XT (an XSLT processor). We'll also see an example of how such integration can create HTML pages that incorporate an XSLT stylesheet directly from a database and how it can convert a database into an XML document. Finally, we'll look at how the DOM API for Databases integrates with an XQL processor. In this article, I make use of existing tools rather than create new tools to illustrate the applications of the SAX and DOM APIs for Databases. I show how to leverage a number of available XML tools to work with a database. All the XML tools I mention are either available for free or free for noncommercial use (though you should, of course, check licensing agreements). Overview of the SAX and DOM APIs The DOM API, on the other hand, follows a tree-like construct. Elements have parent-child relations with other elements. With this API, the parser builds an internal structure such that an application can navigate it in a tree-like fashion. DOM allows an application to have random access to the tree-structured document at the cost of increased memory usage. XML APIs for databases: The
basics <!ELEMENT table rows*> In other words, with an XML API for databases, we can make the database look like an XML document; these APIs present the database as a virtual XML document. We are at the most basic concept of object-oriented design: it is the interface -- not the implementation -- that matters. In our situation, the tools using such an XML API need not care whether they are operating on a database table or an XML file.
Implementing the SAX API for
databases // JDBCInputSource.java In the code above, the constructor takes the information needed to connect to a database and the name of the table to be parsed. The method getConnection() connects to the database and returns a Connection object. Next, we need to implement the SAX parser that uses JDBCInputSource to iterate over database table rows and columns and generates SAX events along the way. To simplify the code, we create an abstract ParserBase class, which implements the org.xml.sax.Parser and has responsibility only for managing various handlers. We then create our SAX parser for the JDBC source JDBCSAXParser that extends the ParserBase class. (To view the code for ParserBase.java, click here.) // JDBCSAXParser.java public void parse (String systemId) throws
SAXException, IOException {
//------------------------------------------------------------------ String
sqlQuery =
getSelectorSQLStatement(source.getTableName());
ResultSet rs =
pstmt.executeQuery();
connection.close(); public void parse(ResultSet rs, String
tableName) ResultSetMetaData
rsmd = rs.getMetaData(); String tableMarker =
getTableMarker(tableName);
_documentHandler.startDocument(); public void parse(String connectionURL,
String userName, String
passwd,
//------------------------------------------------------------------ protected String getTableMarker(String
tableName) { Let's examine the code in more detail. JDBCSAXParser includes several overloaded parse() methods. In the list below, the org.xml.sax.Parser interface requires implementing the parse(InputSource) and parse(String) methods. The other parse() methods simplify the code and allow derived classes to override them to modify the parser behavior. The parse(InputSource) method calls the parse(JDBCInputSource) method if the argument is of type JDBCInputSource; otherwise, it throws a SAXException as it cannot deal with it. The parse(String) method throws a SAXException as the information supplied is not sufficient to access the database. The parse(JDBCInputSource) method gets a Connection object from the input source and executes a query to obtain a ResultSet object. It then calls parse(ResultSet) with this object. The parse(ResultSet, String) method performs the core parsing logic. It iterates over each row in the result set and each column in the rows. The row iteration loop is surrounded by calls to startElement() and endElement() with a table marker as the element-name argument. Similarly, each column iteration loop is surrounded by calls to startElement() and endElement() with a row marker as the element-name argument. In both cases an empty attribute list passes as the second argument to the startElement() methods. On each visit to a column, the generateSAXEventForColumn() method is called with column-name and column-value arguments. The value of a column is accessed by the getString() method on the result-set object, as we need a string representation of the column data to be notified in the characters() SAX event. The convenience method parse(String, String, String, String)
simply creates a JDBCInputSource object with the arguments passed to it and then
calls the parse(JDBCInputSource) method with it. The generateSAXEventForColumn() method generates events for column data. A null value for a column in a database has a different meaning from a column with an empty string. We capture the difference by not firing any events for a column that has a null value. Another choice for representing a null value in a database is to use a binary attribute like isNull. With this option, a true value will be set for null data; otherwise it will be false. The getTableMarker(), getRowMarker(), and getColumnMarker() methods return reasonable defaults for table, row, and column markers. Derived classes may override these to provide custom markups. The getSelectorSQLStatement() method returns a "select * from
<tableName>" string. Derived classes can override it to provide a
different select query string to offer database-level filtering. # portfolio.prop The story so
far ... The parser does not incorporate relational information. That can be solved by using a XPointer/XLink to set the reference to a foreign key in a table. A text column in a database may contain marked-up data. A SAX parser for databases should parse those data as well and generate appropriate SAX events. If such functionality is important for an application, it could override generateSAXEventForColumn() and parse the content of the column and generate additional SAX events. In databases, a table contains an unordered list of columns; the
order in which columns are stored is not important. An XML DTD, on the other
hand, does not have a way to describe an unordered collection of child elements.
It is desirable to present only a selected part of a table as a document based on some query. While XML tools can do the filtering, databases are better at it. The getSelectorSQLStatement() method can be overridden to return the appropriate select query string. The parser uses the getString() method on the result-set object
to obtain the string representation of the value in a column. This works fine
for columns with text, numbers, and so on, but it does not work well with binary
data. While binary data can be represented as text, that may not be suitable for
certain tasks. The parser also does not deal with user-defined types available
with SQL3/JDBC 2.0. Implementing the DOM API for
databases Class JDBCDOMParser implements the DOM API for Databases: // JDBCDOMParser.java The implementation for class JDBCDOMParser is simple. It uses the XmlDocumentBuilder class provided by JAXP to build a DOM document from a SAX event stream. The JDBCDOMParser has only one method: createDocument(), which takes a JDBC data source as the argument. The method creates a JDBCSAXParser and sets it as a parser for an XmlDocumentBuilder object. It then fires the parsing and returns the resulting document from the XmlDocumentBuilder object. Internally, the XmlDocumentBuilder object responds to the SAX events generated by the JDBCSAXParser object by building a DOM document. Using the SAX API for databases We wrap the logic of creating a SAX source for a given database source and processing it with the given XSLT stylesheet to produce an output file in class JDBCXSLProcessor, which is based on com.jclark.xsl.sax.Driver from XT. The main method takes three arguments: a database property file, an XSLT stylesheet file, and an output file. As we'll see below, we can use this approach to generate HTML pages directly without incurring the penalty of creating an intermediate XML file. Moreover, we'll look at how we can use the integration of the SAX API for databases and XT to convert a database into a nonvirtual XML document. (To view the source code for JDBCXSLProcessor.java, click here.) Generating HTML pages directly from a database using an
XSLT stylesheet (To view the stylesheet createTable.xsl, click here.) Converting a database to XML with an XSLT
stylesheet identity.xsl Note that while an XSLT stylesheet easily performs the identity transformation, it is not very efficient as it goes through the complex general-purpose logic of applying the full stylesheet. This inefficiency can be a particular problem for database tables with large numbers of records. An alternative approach is to write an application to perform the identity transformation. Such an application would listen to SAX events and create XML elements and data in response to them, resulting in an XML document that represents the table in the database. Using the DOM API for databases Integrate the DOM API for Databases with the XQL
processor As an example of integration, I provide a simple shell for querying the XML document obtained from a database table. The class JDBCXQLProcessor creates a shell-like environment, which takes the queries from the user and prints the resulting document. The method processQueries() can work with any Document object -- not just objects created by the JDBCDOMParser. It reads the System.in for the query string, performs the query, and prints the result on System.out. The main() method creates a JDBCInputSource object from its argument and uses it with JDBCDOMParser to obtain a Document object corresponding to the given database table. (To view the code for JDBCXQLProcessor.java, click here.) As a side note, writing a database-to-XML converter is a snap with XMLWriter and JDBCDOMParser. Just get a Document object from JDBCDOMParser and write it to the desired file with XMLWriter.write(Document). Conclusion Resources The complete source code for the implementation of the SAX and
DOM APIs for Databases, as well as for the examples discussed in the article,
can be downloaded in zip format. The zip file also includes self-executing jar
files containing compiled class files. The README.txt file provided in the
top-level directory contains instructions to set up and run the
examples: http://developer.java.sun.com/developerWorks/earlyAccess/xml Ramnivas works at Real-Time Innovations, where he is working to design and develop ControlShell, a component-based programming framework for complex real-time systems. Reprinted with permission from JavaWorld magazine.
Copyright Web Publishing Inc., an IDG Communications company. Register for
JavaWorld
alerts. 如果您希望与本文章的作者或其所在机构,进一步交流,请联系:畅享网 姜小姐 jill.jiang@amteam.org | 021-51096826-112 | 在线联系 |
节能与优化IT 企业CIO过冬良策当前金融危机的影响还在继续漫延,很多企业都在苦寻过冬的良策,在这种情况下,节能与优化技术与产品无疑成为CIO们关注的首要对象,本次选题就是针对节能与优化IT来为CIO们提供过冬的良…… |
|
|