Oracle® XML DB Developer's Guide 10g Release 1 (10.1) Part Number B10790-01 |
|
|
View PDF |
This chapter provides a guideline for using the C API for XML with Oracle XML DB.
This chapter contains these topics:
The C API for XML is used for both XDK (XML Developer's Kit) and Oracle XML DB. It is a C-based DOM API for XML. It can be used for XML either inside or outside the database. Here DOM refers to compliance with the World Wide Web Consortium (W3C) DOM 2.0 Recommendation. This API also includes non-standard performance improving extensions used as follows:
In XDK, for traditional XML storage
In Oracle XML DB, for XML stored as an XMLType
column in a table
Note: Use this new C API for XML for any new XDK and Oracle XML DB applications. C DOM functions from prior releases are supported only for backward compatibility, but will not be enhanced. |
The C API for XML is implemented on XMLType
in Oracle XML DB. In the W3C DOM Recommendation, the term document is used in a broad sense (URI, file system, memory buffer, standard input and output). The C API for XML is a combined programming interface that includes all functionality needed by both XDK and Oracle XML DB applications. It provides for XSLT and XML Schema implementations. Although DOM 2.0 Recommendation was followed closely, some naming changes were required for mapping from the objected-oriented DOM 2.0 Recommendation to the flat C namespace. For example, the method getName()
was renamed to getAttrName()
.
C API for XML supersedes existing APIs. In particular, the oraxml
interface (top-level, DOM, SAX, and XSLT) and oraxsd.h
(Schema) interfaces will be deprecated in a future release.
Oracle XML DB provides support for storing and manipulating XML instances using the XMLType datatype. These XML instances can be accessed and manipulated using the Oracle Call Interface (OCI) in conjunction with the C DOM API for XML.
The main flow for an application program would involve initializing the usual OCI handles such as server handle and statement handle followed by initialization of an XML Context. The user program can then either operate on XML instances in the back end or create new instances on the client side. The initialized XML context can be used with all the C DOM functions.
XML data stored in Oracle XML DB can be accessed on the client side using the C DOM structure xmldocnode
. This structure can be used for binding, defining and operating on XML values in OCI statements.
An XML context is a required parameter to all the C DOM API functions. This context encapsulates information pertaining to data encoding, error message language and such. This contents of this opaque context are different for XDK applications and Oracle XML DB.
For Oracle XML DB, there are two OCI functions provided to initialize an XML context. The function OCIXmlDbInitXmlCtx()
is used to initialize the context while OCIXmlDbFreeXmlCtx()
tears it down.
Here is the OCIXmlDbFreeXmlCtx()
syntax:
void OCIXmlDbFreeXmlCtx ( xmlctx *xctx);
where parameter, xctx (IN)
is the XML context to terminate.
Here is the OCIXmlDbInitXmlCtx()
syntax:
xmlctx *OCIXmlDbInitXMlCtx ( OCIEnv *envhp, OCISvcHp *svchp, OCIError *errhp, ocixmldbparam *params, ub4 num_params );
where Table 13-1 lists the parameters.
Table 13-1 OCIXmlDbInitXMlCtx Parameters
Parameter | Description |
---|---|
envhp (IN) |
The OCI environment handle. |
svchp (IN) |
The OCI service handle. |
errhp (IN) |
The OCI error handle |
params (IN) |
Optional values in this array as follows:
OCI duration. Default value is void (*err_handler) (sword errcode, (CONST OraText *) errmsg);void (*err_handler) (sword errcode, (CONST OraText *) errmsg); |
num_params (IN) |
Number of parameters to be read from params . |
In Oracle XML DB, to initialize and terminate the XML context, use the functions OCIXmlDbInitXmlCtx()
and OCIXmlDbFreeXmlCtx()
, respectively, as shown in the following example. These examples are found in header file ocixmldb.h
and used with the C API for XML:
Example 13-1 Using OCI and C API for XML with Oracle XML DB
#ifndef XML_ORACLE #include <xml.h> #endif #ifndef OCIXML_ORACLE #include <ocixml.h> #endif #ifndef OCI_ORACLE #include <oci.h> #endif ... typedef enum { XCTXINIT_OCIDUR = 1, XCTXINIT_ERRHDL = 2 } ocixmldbpname; typdef struct ocixmldbparam { ociXmlDbPName name_ocixml dbpname; void *value_ocixmldbparam; } ocixmldbparam;
The following code shows how to perform operations with the C API for XML:
{ OCIStmt *stmthp = (OCIStmt *)0; xmlctx *xctx = (xmlctx *)0; ocixmldbparam params[NUM_PARAMS]; OCIType *xmltdo = (OCIType *)0; OCIDuration dur = OCI_DURATION_SESSION; text *sel_xml_stmt = (text*)"SELECT xml_col FROM tkpgxucm_tab"; OraText *xpathexpr = (OraText *)"/name"; sword status = 0; /* Allocate statement handle for SQL executions */ if (status=OCIHandleAlloc((dvoid *)ctxptr->envhp, (dvoid **)&stmthp, (ub4)OCI_HTYPE_STMT, (CONST size_t)0, (dvoid **)0)) { return OCI_ERROR; } /* Get an XML context */ params[0].name_xmlctx_param = XCTXINIT_OCIDUR; params[0].value_xmlctx_param = &dur; /* Initialize an XML context */ xctx = OCIXmlDbInitXMlCtx (ctxptr->envhp, ctxptr->svchp, ctxptr->errhp, params, 1); /* Do unified C API operations next */ ... /* Free the allocations associated with the context */ OCIXmlDbFreeXMlCtx(xctx); }
OCI applications operating on XML typically operate on XML data stored in the server and also on XML data created on the client. This section explains these two access methods in more detail.
XML data on the server can be operated on the client using regular OCI statement calls. Similar to other object instances, users can bind and define XMLType values using xmldocnode
. OCI statements can be used to select XML data from the server and this can be used in the C DOM functions directly. Similarly, the values can be bound back to SQL statements directly.
New XMLType
instances on the client can be constructed using the XmlLoadDom()
calls. You first have to initialize the xmlctx
as in the preceding example. The XML data itself can be constructed from a user buffer, local file, or URI. The return value from these is a (xmldocnode *
) that can be used in the rest of the common C API. Finally, the (xmldocnode *
) can be cast to a (void*
) and directly provided as the bind value if required.Empty XMLType
instances can be constructed using the XMLCreateDocument()
call. This would be equivalent to an OCIObjectNew()
for other types. You can operate on the (xmldocnode*
) returned by the preceding call and finally cast it to a (void*
) if it needs to be provided as a bind value.
Table 13-2 provides the XMLType
functional equivalent of common XML operations.
Table 13-2 Common XMLType Operations in C
Description | C API XMLType Function |
---|---|
Create empty XMLType instance |
XmlCreateDocument() |
Create from a source buffer | XmlLoadDom() |
Extract an XPath expression | XmlXPathEvalexpr() and family |
Transform using an XSLT style sheet | XmlXslProcess() and family |
Check if an XPath exists | XmlXPathEvalexpr() and family |
Is document schema-based? | XmlDomIsSchemaBased() |
Get schema information | XmlDomGetSchema() |
Get document namespace | XmlDomGetNodeURI() |
Validate using schema | XmlSchemaValidate() |
Obtain DOM from XMLType | Cast (void *) to (xmldocnode *) |
Obtain XMLType from DOM | Cast (xmldocnode *) to (void *) |
Example 13-2 Constructing an XML Schema-Based Document Using DOM API and Saving it to Oracle Database
static oratext tlpxml_test_sch[] = "<TOP xmlns='example1.xsd'\n\ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \n\ xsi:schemaLocation='example1.xsd example1.xsd'/>"; void example1() { OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIDuration dur; OCIType *xmltdo = (OCIType *) 0; xmldocnode *doc; ocixmldbparam params[1]; xmlnode *quux, *foo, *foo_data; xmlerr err; sword status = 0; /* Initialize envhp, svchp, errhp, dur, stmthp */ /* ........ */ /* Get an xml context */ params[0].name_ocixmldbparam = XCTXINIT_OCIDUR; params[0].value_ocixmldbparam = &dur; xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1); /* Start processing */ printf("Supports XML 1.0: %s\n", XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ? "YES" : "NO"); /* Parsing a schema-based document */ if (!(doc = XmlLoadDom(xctx, &err, "buffer", tlpxml_test_sch, "buffer_length", sizeof(tlpxml_test_sch)-1, "validate", TRUE, NULL))) { printf("Parse failed, code %d\n"); return; } /* Create some elements and add them to the document */ top = XmlDomGetDocElem(xctx, doc); quux = (xmlnode *) XmlDomCreateElem(xctx ,doc, (oratext *) "QUUX"); foo = (xmlnode *) XmlDomCreateElem(xctx, doc, (oratext *) "FOO"); foo_data = (xmlnode *) XmlDomCreateText(xctx, doc, (oratext *) "foo's data"); foo_data = XmlDomAppendChild(xctx, (xmlnode *) foo, (xmlnode *) foo_data); foo = XmlDomAppendChild(xctx, quux, foo); quux = XmlDomAppendChild(xctx, top, quux); XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL); XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL); /* Insert the document to my_table */ ins_stmt = "insert into my_table values (:1)"; status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS", (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE", (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0, (ub4) 0, dur, OCI_TYPEGET_HEADER, (OCIType **) &xmltdo)) ; if (status == OCI_SUCCESS) { exec_bind_xml(svchp, errhp, stmthp, (void *)doc, xmltdo, ins_stmt)); } /* free xml ctx */ OCIXmlDbFreeXmlCtx(xctx); } /*--------------------------------------------------------*/ /* execute a sql statement which binds xml data */ /*--------------------------------------------------------*/ sword exec_bind_xml(svchp, errhp, stmthp, xml, xmltdo, sqlstmt) OCISvcCtx *svchp; OCIError *errhp; OCIStmt *stmthp; void *xml; OCIType *xmltdo; OraText *sqlstmt; { OCIBind *bndhp1 = (OCIBind *) 0; sword status = 0; OCIInd ind = OCI_IND_NOTNULL; OCIInd *indp = &ind; if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)sqlstmt, (ub4)strlen((char *)sqlstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) { return OCI_ERROR; } if(status = OCIBindByPos(stmthp, &bndhp1, errhp, (ub4) 1, (dvoid *) 0, (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) { return OCI_ERROR; } if(status = OCIBindObject(bndhp1, errhp, (CONST OCIType *) xmltdo, (dvoid **) &xml, (ub4 *) 0, (dvoid **) &indp, (ub4 *) 0)) { return OCI_ERROR; } if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) { return OCI_ERROR; } return OCI_SUCCESS; }
Example 13-3 Retrieving a Document From Oracle Database and Modifying it Using the DOM API
sword example2() { OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIDuration dur; OCIType *xmltdo_p=(OCIType *) 0;; xmldocnode *doc; xmlnodelist *item_list; ub4 ilist_l; ocixmldbparam params[1]; text *sel_xml_stmt = (text *)"SELECT xml_col FROM my_table"; ub4 xmlsize = 0; sword status = 0; OCIDefine *defnp = (OCIDefine *) 0; /* Initialize envhp, svchp, errhp, dur, stmthp */ /* ........ */ /* Get an xml context */ params[0].name_ocixmldbparam = XCTXINIT_OCIDUR; params[0].value_ocixmldbparam = &dur; xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1); /* Start processing */ if(status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS", (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE", (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0, (ub4) 0, dur, OCI_TYPEGET_HEADER, (OCIType **) &xmltdo_p)) { return OCI_ERROR; } if(!(xmltdo_p)) { printf("NULL tdo returned\n"); return OCI_ERROR; } if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)selstmt, (ub4)strlen((char *)selstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) { return OCI_ERROR; &&&&&&&&} if(status = OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0, (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)) { return OCI_ERROR;} if(status = OCIDefineObject(defnp, errhp, (OCIType *) xmltdo_p, (dvoid **) &doc, &xmlsize, (dvoid **) 0, (ub4 *) 0)) { return OCI_ERROR; } if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) { return OCI_ERROR; } /* We have the doc. Now we can operate on it */ printf("Getting Item list...\n"); item_list = XmlDomGetElemsByTag(xctx, (xmlelemnode *) elem, (oratext *) "Item"); ilist_l = XmlDomGetNodeListLength(xctx, item_list); printf(" Item list length = %d \n", ilist_l); for (i = 0; i < ilist_l; i++) { elem = XmlDomGetNodeListItem(xctx, item_list, i); printf("Elem Name:%s\n", XmlDomGetNodeName(xctx, fragelem)); XmlDomRemoveChild(xctx, fragelem);} XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL); /* free xml ctx */ OCIXmlDbFreeXmlCtx(xctx); return OCI_SUCCESS;}