Skip Headers
Oracle® XML DB Developer's Guide
10g Release 2 (10.2)

Part Number B14259-02
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

14 Using the C API for XML

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"

Overview of the C API for XML (XDK and Oracle XML DB)

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:

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.

Using OCI and the C API for XML with Oracle XML DB

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.

XML Context Parameter

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.

OCIXmlDbInitXmlCtx() Syntax

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

envhp (IN)

The OCI environment handle.

svchp (IN)

The OCI service handle.

errhp (IN)

The OCI error handle.

params (IN)

An array of optional values:

  • OCI duration. Default value is OCI_DURATION_SESSION.

  • Error handler, which is a user-registered callback:

    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.


OCIXmlDbFreeXmlCtx() Syntax

The syntax of function OCIXmlDbFreeXmlCtx() is as follows, where parameter xctx (IN) is the XML context to terminate.:

void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

Initializing and Terminating an XML Context

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 Usage

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.

Accessing XMLType Data From the Back End

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.

Creating XMLType Instances on the Client

You can construct new XMLType instances on the client using XmlLoadDom(), as follows:

  1. Initialize the xmlctx as in Example 14-1.

  2. 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.

  3. 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.

Common XMLType Operations in C

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 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 *)


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.