This chapter provides a guideline for using the C API for XML with Oracle XML DB.
This chapter contains these topics:
See Also:
Oracle XML Developer's Kit Programmer's Guide "XML Parser for C"The C API for XML is used for both XDK (XML Developer's Kit) and Oracle XML DB. It is a C-based DOMFoot 1 API for XML. It can be used for XML data that is inside or outside the database. This API also includes performance-improving extensions that you can use:
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 the functionality needed by XDK and Oracle XML DB applications. It provides 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()
.
The 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 Parameter. 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 opaque context encapsulates information about the data encoding, the error message language, and so on. The contents of the context are different for Oracle XDK applications and Oracle XML DB. For Oracle XML DB, there are two OCI functions that initialize (OCIXmlDbInitXmlCtx()
) and terminate (OCIXmlDbFreeXmlCtx()
) an XML context.
The syntax of function OCIXmlDbInitXmlCtx()
is as follows:
xmlctx *OCIXmlDbInitXMlCtx (OCIEnv *envhp, OCISvcHp *svchp, OCIError *errhp, ocixmldbparam *params, ub4 num_params );
Table 14-1 describes the parameters.
Table 14-1 OCIXmlDbInitXMlCtx() Parameters
Parameter | Description |
---|---|
|
The OCI environment handle. |
|
The OCI service handle. |
|
The OCI error handle. |
|
An array of optional values:
|
|
Number of parameters to be read from |
Example 14-1 is a C program that uses the C DOM API to construct an XML document and save it to Oracle Database in table my_table
. It calls OCI functions OCIXmlDbInitXmlCtx()
and OCIXmlDbFreeXmlCtx()
to initialize and terminate the XML context. These OCI functions are defined in header file ocixmldb.h
.
The C code in Example 14-1 assumes that the following SQL code has first been executed to create table my_table
in database schema:
CONNECT CAPIUSER/CAPIUSER CREATE TABLE my_table OF XMLType;
Example 14-2 queries table my_table
to show the data that was inserted by Example 14-1.
Example 14-1 Using OCIXmlDbInitXmlCtx() and OCIXmlDbFreeXmlCtx()
This example shows how to use OCI functions OCIXmlDbInitXmlCtx()
and OCIXmlDbFreeXmlCtx()
to initialize and terminate the XML context. It constructs an XML document using the C DOM API and saves it to the database. The code uses helper functions exec_bind_xml
, init_oci_handles
, and free_oci_handles
, which are not listed here. The complete listing of this example, including the helper functions, can be found in Appendix D, "Oracle-Supplied XML Schemas and Examples", "Initializing and Terminating an XML Context (OCI)".
#ifndef S_ORACLE #include <s.h> #endif #ifndef ORATYPES_ORACLE #include <oratypes.h> #endif #ifndef XML_ORACLE #include <xml.h> #endif #ifndef OCIXML_ORACLE #include <ocixml.h> #endif #ifndef OCI_ORACLE #include <oci.h> #endif #include <string.h> typedef struct test_ctx { OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIServer *srvhp; OCIDuration dur; OCISession *sesshp; oratext *username; oratext *password; } test_ctx; /* Helper function 1: execute a sql statement which binds xml data */ STATICF sword exec_bind_xml(OCISvcCtx *svchp, OCIError *errhp, OCIStmt *stmthp, void *xml, OCIType *xmltdo, OraText *sqlstmt); /* Helper function 2: Initialize OCI handles and connect */ STATICF sword init_oci_handles(test_ctx *ctx); /* Helper function 3: Free OCI handles and disconnect */ STATICF sword free_oci_handles(test_ctx *ctx); void main() { test_ctx temp_ctx; test_ctx *ctx = &temp_ctx; OCIType *xmltdo = (OCIType *) 0; xmldocnode *doc = (xmldocnode *)0; ocixmldbparam params[1]; xmlnode *quux, *foo, *foo_data, *top; xmlerr err; sword status = 0; xmlctx *xctx; oratext ins_stmt[] = "insert into my_table values (:1)"; oratext tlpxml_test_sch[] = "<TOP/>"; ctx->username = (oratext *)"CAPIUSER"; ctx->password = (oratext *)"CAPIUSER"; /* Initialize envhp, svchp, errhp, dur, stmthp */ init_oci_handles(ctx); /* Get an xml context */ params[0].name_ocixmldbparam = XCTXINIT_OCIDUR; params[0].value_ocixmldbparam = &ctx->dur; xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1); /* Start processing - first, check that this DOM supports XML 1.0 */ printf("\n\nSupports XML 1.0? : %s\n", XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ? "YES" : "NO"); /* Parse a 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", err); } else { /* Get the document element */ top = (xmlnode *)XmlDomGetDocElem(xctx, doc); /* Print out the top element */ printf("\n\nOriginal top element is :\n"); XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL); /* Print out the document-note that the changes are reflected here */ printf("\n\nOriginal document is :\n"); XmlSaveDom(xctx, &err, (xmlnode *)doc, "stdio", stdout, NULL); /* Create some elements and add them to the document */ quux = (xmlnode *) XmlDomCreateElem(xctx ,doc, (oratext *) "QUUX"); foo = (xmlnode *) XmlDomCreateElem(xctx, doc, (oratext *) "FOO"); foo_data = (xmlnode *) XmlDomCreateText(xctx, doc, (oratext *) "data"); foo_data = XmlDomAppendChild(xctx, (xmlnode *) foo, (xmlnode *) foo_data); foo = XmlDomAppendChild(xctx, quux, foo); quux = XmlDomAppendChild(xctx, top, quux); /* Print out the top element */ printf("\n\nNow the top element is :\n"); XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL); /* Print out the document. Note that the changes are reflected here */ printf("\n\nNow the document is :\n"); XmlSaveDom(xctx, &err, (xmlnode *)doc, "stdio", stdout, NULL); /* Insert the document into my_table */ status = OCITypeByName(ctx->envhp, ctx->errhp, ctx->svchp, (const text *) "SYS", (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE", (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, (OCIType **) &xmltdo); if (status == OCI_SUCCESS) { exec_bind_xml(ctx->svchp, ctx->errhp, ctx->stmthp, (void *)doc, xmltdo, ins_stmt); } } /* Free xml ctx */ OCIXmlDbFreeXmlCtx(xctx); /* Free envhp, svchp, errhp, stmthp */ free_oci_handles(ctx); }
The output from compiling and running this C program is as follows:
Supports XML 1.0? : YES Original top element is : <TOP/> Original document is : <TOP/> Now the top element is : <TOP> <QUUX> <FOO>data</FOO> </QUUX> </TOP> Now the document is : <TOP> <QUUX> <FOO>data</FOO> </QUUX> </TOP>
This is the result of querying the constructed document in my_table
:
SELECT * FROM my_table; SYS_NC_ROWINFO$ --------------- <TOP> <QUUX> <FOO>data</FOO> </QUUX> </TOP> 1 row selected.
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.
You can construct new XMLType
instances on the client using XmlLoadDom()
, as follows:
Initialize the xmlctx
as in Example 14-1.
Construct the XML data from a user buffer, local file, or URI. The return value, a (xmldocnode*
), can be used in the rest of the common C API.
If required, you can cast (xmldocnode *
) to (void*
) and provide it directly as the bind value.
You can construct empty XMLType
instances with XMLCreateDocument()
. This is similar to using OCIObjectNew()
for other types.
Table 14-2 provides the XMLType
functional equivalent of common XML operations.
Table 14-2 Common XMLType Operations in C
Description | C API XMLType Function |
---|---|
Create empty |
|
Create from a source buffer |
|
Extract an XPath expression |
|
Transform using an XSLT style sheet |
|
Check if an XPath exists |
|
Is document schema-based? |
|
Get schema information |
|
Get document namespace |
|
Validate using schema |
|
Obtain DOM from XMLType |
Cast |
Obtain XMLType from DOM |
Cast |
See Also:
Oracle XML Developer's Kit Programmer's Guide "XML Parser for C"Example 14-2 Using the DOM to Count Ordered Parts
This example shows how to use the DOM to determine how many instances of a particular part have been ordered. The part in question has Id
37429158722
. See Appendix D, "Oracle-Supplied XML Schemas and Examples", Example D-4 for the definitions of helper functions exec_bind_xml
, free_oci_handles
, and init_oci_handles
.
#ifndef S_ORACLE #include <s.h> #endif #ifndef ORATYPES_ORACLE #include <oratypes.h> #endif #ifndef XML_ORACLE #include <xml.h> #endif #ifndef OCIXML_ORACLE #include <ocixml.h> #endif #ifndef OCI_ORACLE #include <oci.h> #endif #include <string.h> typedef struct test_ctx { OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIServer *srvhp; OCIDuration dur; OCISession *sesshp; oratext *username; oratext *password; } test_ctx; /* Helper function 1: execute a sql statement which binds xml data */ STATICF sword exec_bind_xml(OCISvcCtx *svchp, OCIError *errhp, OCIStmt *stmthp, void *xml, OCIType *xmltdo, OraText *sqlstmt); /* Helper function 2: Initialize OCI handles and connect */ STATICF sword init_oci_handles(test_ctx *ctx); /* Helper function 3: Free OCI handles and disconnect */ STATICF sword free_oci_handles(test_ctx *ctx); void main() { test_ctx temp_ctx; test_ctx *ctx = &temp_ctx; OCIType *xmltdo = (OCIType *) 0; xmldocnode *doc = (xmldocnode *)0; ocixmldbparam params[1]; xmlnode *quux, *foo, *foo_data, *top; xmlerr err; sword status = 0; xmlctx *xctx; ub4 xmlsize = 0; OCIDefine *defnp = (OCIDefine *) 0; oratext sel_stmt[] = "SELECT SYS_NC_ROWINFO$ FROM PURCHASEORDER"; xmlnodelist *litems = (xmlnodelist *)0; xmlnode *item = (xmlnode *)item; xmlnode *part; xmlnamedmap *attrs; xmlnode *id; xmlnode *qty; oratext *idval; oratext *qtyval; ub4 total_qty; int i; int numdocs; ctx->username = (oratext *)"OE"; ctx->password = (oratext *)"OE"; /* Initialize envhp, svchp, errhp, dur, stmthp */ init_oci_handles(ctx); /* Get an xml context */ params[0].name_ocixmldbparam = XCTXINIT_OCIDUR; params[0].value_ocixmldbparam = &ctx->dur; xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1); /* Start processing */ printf("\n\nSupports XML 1.0? : %s\n", XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ? "YES" : "NO"); /* Get the documents from the database using a select statement */ status = OCITypeByName(ctx->envhp, ctx->errhp, ctx->svchp, (const text *) "SYS", (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE", (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, (OCIType **) &xmltdo); status = OCIStmtPrepare(ctx->stmthp, ctx->errhp, (CONST OraText *)sel_stmt, (ub4) strlen((char *)sel_stmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); status = OCIDefineByPos(ctx->stmthp, &defnp, ctx->errhp, (ub4) 1, (dvoid *) 0, (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT); status = OCIDefineObject(defnp, ctx->errhp, (OCIType *) xmltdo, (dvoid **) &doc, &xmlsize, (dvoid **) 0, (ub4 *) 0); status = OCIStmtExecute(ctx->svchp, ctx->stmthp, ctx->errhp, (ub4) 0, (ub4) 0, (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT); /* Initialize variables */ total_qty = 0; numdocs = 0; /* Loop through all the documents */ while ((status = OCIStmtFetch2(ctx->stmthp, ctx->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT, (ub4)1, (ub4) OCI_DEFAULT)) == 0) { numdocs++; /* Get all the LineItem elements */ litems = XmlDomGetDocElemsByTag(xctx, doc, (oratext *)"LineItem"); i = 0; /* Loop through all LineItems */ while (item = XmlDomGetNodeListItem(xctx, litems, i)) { /* Get the part */ part = XmlDomGetLastChild(xctx, item); /* Get the attributes */ attrs = XmlDomGetAttrs(xctx, (xmlelemnode *)part); /* Get the id attribute and its value */ id = XmlDomGetNamedItem(xctx, attrs, (oratext *)"Id"); idval = XmlDomGetNodeValue(xctx, id); /* We are only interested in parts with id 37429158722 */ if (idval && (strlen((char *)idval) == 11 ) && !strncmp((char *)idval, (char *)"37429158722", 11)) { /* Get the quantity attribute and its value.*/ qty = XmlDomGetNamedItem(xctx, attrs, (oratext *)"Quantity"); qtyval = XmlDomGetNodeValue(xctx, qty); /* Add the quantity to total_qty */ total_qty += atoi((char *)qtyval); } i++; } XmlFreeDocument(xctx, doc); doc = (xmldocnode *)0; } printf("Total quantity needed for part 37429158722 = %d\n", total_qty); printf("Number of documents in table PURCHASEORDER = %d\n", numdocs); /* Free Xml Ctx */ OCIXmlDbFreeXmlCtx(xctx); /* Free envhp, svchp, errhp, stmthp */ free_oci_handles(ctx); }
The output from compiling and running this C program is as follows:
Supports XML 1.0? : YES Total quantity needed for part 37429158722 = 42 Number of documents in table PURCHASEORDER = 132
Footnote Legend
Footnote 1: DOM refers to compliance with the World Wide Web Consortium (W3C) DOM 2.0 Recommendation.