![](resources/join.gif)
![Index](graphics/index-label-3.jpg)
![License](graphics/license-label-3.jpg)
![Install](graphics/install-label-3.jpg)
![](resources/separator.gif)
![Technologies](graphics/technologies-label-3.jpg)
![Infrastructure](graphics/infrastracture-label-3.jpg)
![User Guide](graphics/guide-label-3.jpg)
![Dynamic Content](graphics/dynamic-label-3.jpg)
![](resources/separator.gif)
![XSP Processor](graphics/xsp-label-3.jpg)
![SQL XSP Taglib](graphics/sqltablig-label-3.jpg)
![SQL Processor](graphics/sql-label-1.jpg)
![LDAP Processor](graphics/ldap-label-3.jpg)
![DCP Processor](graphics/dcp-label-3.jpg)
![](resources/separator.gif)
![XSP WD](graphics/wd-xsp-label-3.jpg)
![](resources/separator.gif)
![Javadocs](graphics/ext-36-label-3.jpg)
![](resources/separator.gif)
![Cocoon 2](graphics/cocoon2-label-3.jpg)
![Javadoc XML](graphics/javadoc-label-3.jpg)
![](resources/separator.gif)
![FAQ](graphics/faqs-label-3.jpg)
![Changes](graphics/changes-label-3.jpg)
![Todo](graphics/todo-label-3.jpg)
![](resources/separator.gif)
![Live Sites](graphics/livesites-label-3.jpg)
![](resources/separator.gif)
![Code Repository](graphics/ext-58-label-3.jpg)
![Dev Snapshots](graphics/ext-60-label-3.jpg)
![Mail Archive](graphics/ext-62-label-3.jpg)
![Bug Database](graphics/ext-64-label-3.jpg)
![](resources/close.gif)
|
SQLProcessor is a processor for Cocoon that performs SQL queries, translates the resultset into an XML fragment, and inserts the fragment in the original document. I wrote it because I've got quite a bit of "legacy" data in SQL databases that I wanted to be able to easily access from Cocoon. I believe that servers and data structures capable of storing and retrieving large amounts of XML data natively will arise, obviating the need for this type of middleware. I also believe that it's going to take a while for them to achieve the same performance and stability we've come to expect from SQL databases, hence the current need for SQLProcessor or something like it.
|
Add SQL queries to your XML files. The tagset looks like this:
![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | <query connection="foo_connection">
select name,number,message from foo_table order by name
</query> | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) |
This will be replaced by a tagset that looks like this:
![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | <ROWSET>
<ROW ID="0">
<NAME>Donald Ball</NAME>
<NUMBER>23</NUMBER>
<MESSAGE>
The Illuminati do not exist.
This message paid for by the Illuminati.</MESSAGE
>
</ROW>
... other rows ...
</ROWSET> | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) |
You can also have SQLProcessor substitute values from the servlet request into your query. The syntax for that is:
![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | <query connection="foo_connection">
select name,number,message from foo_table where id={@id} order by name
</query> | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) |
This is, of course, highly configurable by setting attributes of the query tag. A partial list of attributes is:
doc-element - The tag with which to wrap the whole shebang. Default is ROWSET. If an empty string is specified, e.g. doc-element="", the whole shebang will not be wrapped.
row-element - The tag with which to wrap each row. Default is ROW. Same deal as with doc-element.
tag-case - The case in which to present the column name tags. Default is "preserve", meaning use whatever the JDBC driver likes to call the columns. Options are "upper" for forced uppercase (boo) or "lower" for forced lowercase (yay).
null-indicator - What do we do with null columns. default is to not print anything for null columns, not even a column tag. If this is set to "y" or "yes", we add a NULL="YES" attribute to the column and put an empty string inside.
id-attribute - What is the name of the attribute that uniquely identifies the rows? Default is ID. This is, of course, meaningless if row-element is set to an empty string.
id-attribute-column - Which column should we use for the id attribute value (think primary key column). Default is to use the offset of this row in the query's resultset.
max-rows - How many rows should we display
skip-rows - How many rows should we skip before starting to display rows
variable-left-delimiter - What string delimits variables in the query on the left side? Default is {@.
variable-right-delimiter - What string delimits variables in the query on the right side? Default is }.
|
URL request parameter substitution using {@var} is fine for many situations, but is inadequate for handling queries whose conditions are dependent on the state of many variables. To accomodate these queries, you can specify the name of a subclass of SQLQueryCreator that will create the query string. The method that should be overridden is:
![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | public String getQuery(Connection conn, String query,
Element query_element, Properties query_props, Hashtable parameters)
throws Exception; | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) | ![](resources/void.gif) |
This looks like a lot of parameters. I didn't figure that it made sense to deny any of the potential information available to the query creator. Just ignore what you don't care about. The parameters that deserve explanation are query_props, which is a Properties object containing all of the attribute values of the query tag, keyed by name. The parameters table is passed from cocoon to its processors, and contains lots of informatin, notable the original HttpServletRequest, keyed by the string "request".
You specify the particular subclass of SQLQueryCreator in the creator attribute of the query tag. It's probably easiest if you put your query creators in a package, e.g. com.webslingerZ.cocoon.ComplexQueryCreator.
One utility method is provided for your convenience. The SQLEscape method should parse a string for apostrophes and replace them with whichever string their database likes to use instead. It's not working correctly for my database drivers, so the default getQuery method does not use it. If anyone can suggest the correct way to go about doing this, please contact me with your suggestion or, ideally, a patch.
This is probably an overly complex way to handle most complex queries. It is hopefully the case that a more sophisticated variable substitution scheme or alternate attribute set will arise that accomodates more common complex queries without the need to write Java code. There is also some rationale for making SQLQueryCreator an interface. I welcome suggestions along these lines.
|
I sure hope this is useful to you. It's proving to be very useful to me. The DTD used here is a superset of that used by Oracle's XSQL servlet (which provides no methods for specifying alternate variable delimiters, creating complex queries, query default attributes, or error handling). Technical notes for the XSQL servlet are available - note you apparantly must now fill out an annoying survey to get access to this page. We're sharing the DTD with the tacit approval of Steve Meunch, who kindly pointed me in that direction when he saw a) how similar our methodologies were and b) how horrible my original DTD was. Thanks also go out to Stefano Mazzocchi, who started this whole cocoon business in the first place, and Ricardo Rocha, whose DCP processor provided the framework for SQLProcessor's parent, XMLResultSet. Stefano Malimpensa has suggested many useful features that are beginning to make their way into the code.
|
- support for a <querydefs> tag for setting default query attributes
- time-based caching of query results
- simple postprocessing of SQL values (e.g. date formats)
- error message display
|
|
|