[ruby-oci8-devel] About XML DB support in Ruby-OCI8

Liming Lian liming.lian at oracle.com
Thu May 22 08:27:59 EDT 2008

Hi all,

Continue reporting my experiments on XMLDB support implementation.

> Maybe we can use the same approach as the Lazy XML loading. We don't 
> retrieve the entire XML data when issue the cursor fetch operation, 
> but instead maintain a client side object with an initialized XML 
> context and retrieved xmlnode which is a pointer to XML data 
> requested. Whenever users process the data of this xml doc such as 
> retrieving child nodes, xpath querying and so on, we use corresponding 
> XDK api to process data requested in database and retrieve the result 
> to the client side. Or we can say, we add a ruby-oci8 class to wrap 
> XDK api for processing xml data in database in Lazy XML loading mode. 
> IMO, this may somehow increase the performance of XMLDB support in 
> Ruby-OCI8.
I added an class OCI8::XDB::XMLnode which wraps following C structure:

typedef struct {
    oci8_base_t base;
    struct xmlctx *xctx; //XML Context
    xmlnode *node; // Pointer to a single xml node
} oci8_xmlnode_t;

When fetching xmltype from database, we get an "xmldocnode" pointing to 
the XML document. We create an instance of XMLNode to hold this 
"xmldocnode" and the initialized "xmlctx". When we need to further 
process  the xml doc, for example to get the root element, we can 
retrieve the "xmldocnode" from the object and use XDK api 
"XmlDomGetDocElem" to retrieve root node. Then a new instance of XMLnode 
presenting root element will be created to wrap the "xmlnode" returned 
by "XmlDomGetDocElem". All the nodes in the xml doc can be accessed and 
presented on the client side in the same way with different XDK api 
calls. Since the XMLNode object holds the internal "xmlnode" pointer, we 
can perform all the operations on that node by leveraging various XDK 
apis. The benefit of this approach is that we don't need to go through 
the whole tree of xml doc but only store the single "xmldocnode" at the 
xmltype fetch stage. We can call it "lazy" loading, we load only the 
nodes we demand.

The disadvantage of this implementation is also obvious. Since it 
doesn't traverse the whole xml tree at xmltype fetch stage and a single 
node in an xml document is hard to be identified, it is generally 
difficult to maintain a structure such as hash table to store the nodes 
we have visited. So every time we use XDK api such as 
XmlDomGetFirstChild or XmlDomGetElemById to visit a node, we have to 
create a new XMLNode instance to wrap the "xmlnode" returned, even this 
node has been visited before.

Take a look at following example:

       /       \
    n1       n2
   /  \        /  \
 n3 n4  n5 n6

root = doc.root
n3_1 = doc.get_elem_by_tag('n3')[0]
n3_2 = doc.get_elem_by_tag('n3')[0]

Here:  "get_element_by_tag" returns elements with tag name "n3".  "n3_1" 
and "n3_2" are all instance of "XMLNode", but they have not the same 


More information about the ruby-oci8-devel mailing list