Skip Headers

Oracle® XML DB Developer's Guide
10g Release 1 (10.1)

Part Number B10790-01
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
Feedback

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

5 XML Schema Storage and Query: The Basics

This chapter introduces XML Schema and explains how to register and use XML Schema with Oracle XML DB. It also describes how to delete and update XML Schema and create storage structures for schema-based XML. It discusses simpleType and complexType mapping from XML to SQL storage types as well as XPath rewrite fundamentals.

This chapter contains these topics:

Introducing XML Schema

The XML Schema Recommendation was created by the World Wide Web Consortium (W3C) to describe the content and structure of XML documents in XML. It includes the full capabilities of Document Type Definitions (DTDs) so that existing DTDs can be converted to XML Schema. XML Schemas have additional capabilities compared to DTDs.

XML Schema and Oracle XML DB

XML Schema is a schema definition language written in XML. It can be used to describe the structure and various other semantics of conforming instance documents. For example, the following XML Schema definition, purchaseOrder.xsd, describes the structure and other properties of purchase order XML documents.

This manual refers to an XML schema definition as an XML Schema.

Example 5-1 XML Schema Definition, purchaseOrder.xsd

The following is an example of an XML Schema. It declares a complexType called purchaseOrderType and a global element PurchaseOrder of this type.

<xs:schema
  targetNamespace="http://xmlns.oracle.com/xdb/documentation/purchaseOrder"
  xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
  <xs:element name="PurchaseOrder" type="po:PurchaseOrderType"/>
    <xs:complexType name="PurchaseOrderType">
      <xs:sequence>
        <xs:element name="Reference" type="po:ReferenceType"/>
        <xs:element name="Actions" type="po:ActionsType"/>
        <xs:element name="Reject" type="po:RejectionType" minOccurs="0"/>
        <xs:element name="Requestor" type="po:RequestorType"/>
        <xs:element name="User" type="po:UserType"/>
        <xs:element name="CostCenter" type="po:CostCenterType"/>
        <xs:element name="ShippingInstructions" 
                    type="po:ShippingInstructionsType"/>
        <xs:element name="SpecialInstructions" 
                    type="po:SpecialInstructionsType"/>
        <xs:element name="LineItems" type="po:LineItemsType"/>
        <xs:element name="Notes" type="po:NotesType"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="LineItemsType">
      <xs:sequence>
        <xs:element name="LineItem" type="po:LineItemType" 
                    maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="LineItemType">
      <xs:sequence>
        <xs:element name="Description" type="po:DescriptionType"/>
        <xs:element name="Part" type="po:PartType"/>
      </xs:sequence>
      <xs:attribute name="ItemNumber" type="xs:integer"/>
    </xs:complexType>
    <xs:complexType name="PartType">
      <xs:attribute name="Id">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:minLength value="10"/>
            <xs:maxLength value="14"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:attribute>
      <xs:attribute name="Quantity" type="po:moneyType"/>
      <xs:attribute name="UnitPrice" type="po:quantityType"/>
    </xs:complexType>
    <xs:simpleType name="ReferenceType">
      <xs:restriction base="xs:string">
        <xs:minLength value="18"/>
        <xs:maxLength value="30"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:complexType name="ActionsType">
      <xs:sequence>
        <xs:element name="Action" maxOccurs="4">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="User" type="po:UserType"/>
              <xs:element name="Date" type="po:DateType" minOccurs="0"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="RejectionType">
      <xs:all>
        <xs:element name="User" type="po:UserType" minOccurs="0"/>
        <xs:element name="Date" type="po:DateType" minOccurs="0"/>
        <xs:element name="Comments" type="po:CommentsType" minOccurs="0"/>
      </xs:all>
    </xs:complexType>
    <xs:complexType name="ShippingInstructionsType">
      <xs:sequence>
        <xs:element name="name" type="po:NameType" minOccurs="0"/>
        <xs:element name="address" type="po:AddressType" minOccurs="0"/>
        <xs:element name="telephone" type="po:TelephoneType" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="moneyType">
      <xs:restriction base="xs:decimal">
        <xs:fractionDigits value="2"/>
        <xs:totalDigits value="12"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="quantityType">
      <xs:restriction base="xs:decimal">
        <xs:fractionDigits value="4"/>
        <xs:totalDigits value="8"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="UserType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="10"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="RequestorType">
      <xs:restriction base="xs:string">
        <xs:minLength value="0"/>
        <xs:maxLength value="128"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="CostCenterType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="4"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="VendorType">
      <xs:restriction base="xs:string">
        <xs:minLength value="0"/>
        <xs:maxLength value="20"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="PurchaseOrderNumberType">
      <xs:restriction base="xs:integer"/>
    </xs:simpleType>
    <xs:simpleType name="SpecialInstructionsType">
      <xs:restriction base="xs:string">
        <xs:minLength value="0"/>
        <xs:maxLength value="2048"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="NameType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="20"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="AddressType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="256"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="TelephoneType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="24"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="DateType">
      <xs:restriction base="xs:date"/>
    </xs:simpleType>
    <xs:simpleType name="CommentsType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="2048"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="DescriptionType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="256"/>
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="NotesType">
      <xs:restriction base="xs:string">
        <xs:minLength value="1"/>
        <xs:maxLength value="32767"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:schema>

Example 5-2 XML Document, purchaseOrder.xml Conforming to XML Schema, purchaseOrder.xsd

The following is an example of an XML document that conforms to XML Schema purchaseOrder.xsd:

<po:PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder" 
  xsi:schemaLocation=
    "http://xmlns.oracle.com/xdb/documentation/purchaseOrder
     http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd">
  <Reference>SBELL-2002100912333601PDT</Reference>
  <Actions>
    <Action>
      <User>SVOLLMAN</User>
    </Action>
  </Actions>
  <Reject/>
  <Requestor>Sarah J. Bell</Requestor>
  <User>SBELL</User>
  <CostCenter>S30</CostCenter>
  <ShippingInstructions>
    <name>Sarah J. Bell</name>
    <address>400 Oracle Parkway
             Redwood Shores
             CA
             94065
             USA
    </address>
    <telephone>650 506 7400</telephone>
  </ShippingInstructions>
  <SpecialInstructions>Air Mail</SpecialInstructions>
  <LineItems>
    <LineItem ItemNumber="1">
      <Description>A Night to Remember</Description>
      <Part Id="715515009058" UnitPrice="39.95" Quantity="2"/>
    </LineItem>
    <LineItem ItemNumber="2">
      <Description>The Unbearable Lightness Of Being</Description>
      <Part Id="37429140222" UnitPrice="29.95" Quantity="2"/>
    </LineItem>
    <LineItem ItemNumber="3">
      <Description>Sisters</Description>
      <Part Id="715515011020" UnitPrice="29.95" Quantity="4"/>
    </LineItem>
  </LineItems>
  <Notes>Section 1.10.32 of &quot;de Finibus Bonorum et Malorum&quot;, 
         written by Cicero in 45 BC
 
&quot;Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
 doloremque laudantium, totam rem aperiam, eaque ips
a quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt
 explicabo. Nemo enim ipsam voluptatem quia voluptas s
it aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui
 ratione voluptatem sequi nesciunt. Neque porro quisqua
m est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed
 quia non numquam eius modi tempora incidunt ut labore
 et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis
 nostrum exercitationem ullam corporis suscipit laborios
am, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure
 reprehenderit qui in ea voluptate velit esse quam nihil moles
tiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
 pariatur?&quot;
 
1914 translation by H. Rackham
 
&quot;But I must explain to you how all this mistaken idea of denouncing
 pleasure and praising pain was born and I will give you a c
omplete account of the system, and expound the actual teachings of the great
 explorer of the truth, the master-builder of human happ
iness. No one rejects, dislikes, or avoids pleasure itself, because it is
 pleasure, but because those who do not know how to pursue
pleasure rationally encounter consequences that are extremely painful. Nor again
 is there anyone who loves or pursues or desires to
obtain pain of itself, because it is pain, but because occasionally
 circumstances occur in which toil and pain can procure him some
great pleasure. To take a trivial example, which of us ever undertakes laborious
 physical exercise, except to obtain some advantage
from it? But who has any right to find fault with a man who chooses to enjoy a
 pleasure that has no annoying consequences, or one wh
o avoids a pain that produces no resultant pleasure?&quot;
 
Section 1.10.33 of &quot;de Finibus Bonorum et Malorum&quot;, written by Cicero
in 45 BC
 
&quot;At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis
 praesentium voluptatum deleniti atque corrupti quos
dolores et quas molestias excepturi sint occaecati cupiditate non provident,
 similique sunt in culpa qui officia deserunt mollitia a
nimi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et
 expedita distinctio. Nam libero tempore, cum soluta nobis
 est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere
 possimus, omnis voluptas assumenda est, omnis dolor
 repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum
 necessitatibus saepe eveniet ut et voluptates repudiandae
 sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente
 delectus, ut aut reiciendis voluptatibus maiores alias
consequatur aut perferendis doloribus asperiores repellat.&quot;
 
1914 translation by H. Rackham
 
&quot;On the other hand, we denounce with righteous indignation and dislike men
 who are so beguiled and demoralized by the charms of
 pleasure of the moment, so blinded by desire, that they cannot foresee the pain
 and trouble that are bound to ensue; and equal blam
e belongs to those who fail in their duty through weakness of will, which is the
 same as saying through shrinking from toil and pain
. These cases are perfectly simple and easy to distinguish. In a free hour, when
 our power of choice is untrammelled and when nothin
g prevents our being able to do what we like best, every pleasure is to be
 welcomed and every pain avoided. But in certain circumsta
nces and owing to the claims of duty or the obligations of business it will
 frequently occur that pleasures have to be repudiated an
d annoyances accepted. The wise man therefore always holds in these matters to
 this principle of selection: he rejects pleasures to
secure other greater pleasures, or else he endures pains to avoid worse
 pains.&quot;
  </Notes>
</po:PurchaseOrder>

Note:

The URL used here (http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd) is simply a name that uniquely identifies the registered XML Schema within the database; it need not be the physical URL at the which the XML Schema document is located. The target namespace of the XML Schema is another URL, different from the XML Schema location URL, which specifies an abstract namespace within which elements and types get declared.

An XML Schema can optionally specify the target namespace URL. If this attribute is omitted, the XML Schema has no target namespace. The target namespace is commonly the same as the URL of the XML Schema.

An XML instance document must specify the namespace of the root element (same as the target namespace of the XML Schema) and the location (URL) of the XML Schema that defines this root element. The location is specified with attribute xsi:schemaLocation. When the XML Schema has no target namespace, use attribute xsi:noNamespaceSchemaLocation to specify the schema URL.


Using Oracle XML DB and XML Schema

Oracle XML DB uses annotated XML Schema as metadata, that is, the standard XML Schema definitions along with several Oracle XML DB-defined attributes. These attributes control how instance XML documents get mapped to the database. Because these attributes are in a different namespace from the XML Schema namespace, such annotated XML Schemas are still legal XML Schema documents.


See Also:

Namespace of XML Schema constructs: http://www.w3.org/2001/XMLSchema

When using Oracle XML DB with XML Schema, you must first register the XML Schema. You can then use the XML Schema URLs while creating XMLType tables, columns, and views. The XML Schema URL, in other words, the URL that identifies the XML Schema in the database, is associated with the schemaurl parameter of registerSchema.

Oracle XML DB provides XML Schema support for the following tasks:

Why We Need XML Schema

As described in Chapter 4, " XMLType Operations ", XMLType is a datatype that facilitates storing XMLType in columns and tables in the database. XML Schemas further facilitate storing XML columns and tables in the database, and they offer you more storage and access options for XML data along with space- performance-saving options.

For example, you can use XML Schema to declare which elements and attributes can be used and what kinds of element nesting, and datatypes are allowed in the XML documents being stored or processed.

XML Schema Provides Flexible XML-to-SQL Mapping Setup

Using XML Schema with Oracle XML DB provides a flexible setup for XML storage mapping. For example:

  • If your data is highly structured (mostly XML), then each element in the XML documents can be stored as a column in a table.

  • If your data is unstructured (all or mostly non-XML data), then the data can be stored in a Character Large Object (CLOB).

Which storage method you choose depends on how your data will be used and depends on the queriability and your requirements for querying and updating your data. In other words, using XML Schema gives you more flexibility for storing highly structured or unstructured data.

XML Schema Allows XML Instance Validation

Another advantage of using XML Schema with Oracle XML DB is that you can perform XML instance validation according to the XML Schema and with respect to Oracle XML repository requirements for optimal performance. For example, an XML Schema can check that all incoming XML documents comply with definitions declared in the XML Schema, such as allowed structure, type, number of allowed item occurrences, or allowed length of items.

Also, by registering XML Schema in Oracle XML DB, when inserting and storing XML instances using Protocols, such as FTP or HTTP, the XML Schema information can influence how efficiently XML instances are inserted.

When XML instances must be handled without any prior information about them, XML Schema can be useful in predicting optimum storage, fidelity, and access.

DTD Support in Oracle XML DB

In addition to supporting XML Schema that provide a structured mapping to object- relational storage, Oracle XML DB also supports DTD specifications in XML instance documents. Though DTDs are not used to derive the mapping, XML processors can still access and interpret the DTDs.

Inline DTD Definitions

When an XML instance document has an inline DTD definition, it is used during document parsing. Any DTD validations and entity declaration handling is done at this point. However, once parsed, the entity references are replaced with actual values and the original entity reference is lost.

External DTD Definitions

Oracle XML DB also supports external DTD definitions if they are stored in the repository. Applications needing to process an XML document containing an external DTD definition such as /public/flights.dtd, must first ensure that the DTD document is stored in Oracle XML DB at path /public/flights.xsd.

Managing XML Schemas Using DBMS_XMLSCHEMA

Before an XML Schema can be used by Oracle XML DB, it must be registered with Oracle Database. You register an XML Schema using the PL/SQL package DBMS_XMLSCHEMA.

Some of the main DBMS_XMLSCHEMA functions are:

Registering Your XML Schema

The main arguments to function registerSchema() are the following:

  • schemaURL – the XML Schema URL. This is a unique identifier for the XML Schema within Oracle XML DB. Convention is that this identifier is in the form of a URL; however, this is not a requirement. The XML Schema URL is used with Oracle XML DB to identify instance documents, by making the schema location hint identical to the XML Schema URL. Oracle XML DB will never attempt to access the Web server identified by the specified URL.

  • schemaDoc – the XML Schema source document. This is a VARCHAR, CLOB, BLOB, BFILE, XMLType, or URIType value.

  • CSID – the character-set ID of the source-document encoding, when schemaDoc is a BFILE or BLOB value.

Example 5-3 Registering an XML Schema Using Package DBMS_XMLSCHEMA

The following code registers the XML Schema at URL http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd. This example shows how to register an XML Schema using the BFILE mechanism to read the source document from a file on the local file system of the database server.

BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    SCHEMAURL => 'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd',
    SCHEMADOC => bfilename('XMLDIR','purchaseOrder.xsd'),
    CSID => nls_charset_id('AL32UTF8'));
END;
/

Storage and Access Infrastructure

As part of registering an XML Schema, Oracle XML DB also performs several tasks that facilitate storing, accessing, and manipulating XML instances that conform to the XML Schema. These steps include:

  • Creating types: When an XML Schema is registered, Oracle Database creates the appropriate SQL object types that enable the structured storage of XML documents that conform to this XML Schema. You can use the Schema annotations to control how these object types are named and generated. See "SQL Object Types" for details.

  • Creating default tables: As part of XML Schema registration, Oracle XML DB generates default XMLType tables for all global elements. You can use schema annotations to control the names of the tables and to provide column-level and table-level storage clauses and constraints for use during table creation.

After registration has completed:

  • XMLType tables and columns can be created that are constrained to the global elements defined by this XML Schema.

  • XML documents conforming to the XML Schema, and referencing it using the XML Schema instance mechanism, can be processed automatically by Oracle XML DB.

Transactional Action of XML Schema Registration

Registration of an XML Schema is non transactional and auto committed as with other SQL DDL operations, as follows:

  • If registration succeeds, then the operation is auto committed.

  • If registration fails, then the database is rolled back to the state before the registration began.

Because XML Schema registration potentially involves creating object types and tables, error recovery involves dropping any such created types and tables. Thus, the entire XML Schema registration is guaranteed to be atomic. That is, either it succeeds or the database is restored to the state before the start of registration.

Managing and Storing XML Schema

XML Schema documents are themselves stored in Oracle XML DB as XMLType instances. XML Schema-related XMLType types and tables are created as part of the Oracle XML DB installation script, catxdbs.sql.

The XML Schema for XML Schemas is called the root XML Schema, XDBSchema.xsd. XDBSchema.xsd describes any valid XML Schema document that can be registered by Oracle XML DB. You can access XDBSchema.xsd through Oracle XML DB repository at /sys/schemas/PUBLIC/xmlns.oracle.com/xdb/XDBSchema.xsd.

Debugging XML Schema Registration

You can monitor the object types and tables created during XML Schema registration by setting the following event before calling DBMS_XMLSCHEMA.registerSchema():

ALTER SESSION SET events='31098 trace name context forever'

Setting this event causes the generation of a log of all the CREATE TYPE and CREATE TABLE statements. The log is written to the user session trace file, typically found in <ORACLE_HOME>/admin/<ORACLE_SID>/udump. This script can be a useful aid in diagnosing problems during XML Schema registration.

SQL Object Types

Assuming that the parameter GENTYPES is set to TRUE when an XML Schema is registered, Oracle XML DB creates the appropriate SQL object types that enable structured storage of XML documents that conform to this XML Schema. By default, all SQL object types are created in the database schema of the user who registers the XML Schema. If the defaultSchema annotation is used, then Oracle XML DB attempts to create the object type using the specified database schema. The current user must have the necessary privileges to perform this.

Example 5-4 Creating SQL Object Types to Store XMLType Tables

For example, when purchaseOrder.xsd is registered with Oracle XML DB, the following SQL types are created.

SQL> DESCRIBE "PurchaseOrderType1668_T"
  
"PurchaseOrderType1668_T" is NOT FINAL
Name                 Null?  Type
-------------------- ------ -------------------------------
SYS_XDBPD$                  XDB.XDB$RAW_LIST_T
Reference                   VARCHAR2(30 CHAR)
Actions                     ActionsType1661_T
Reject                      RejectionType1660_T
Requestor                   VARCHAR2(128 CHAR)
User                        VARCHAR2(10 CHAR)
CostCenter                  VARCHAR2(4 CHAR)
ShippingInstructions        ShippingInstructionsTyp1659_T
SpecialInstructions         VARCHAR2(2048 CHAR)
LineItems                   LineItemsType1666_T
Notes                       VARCHAR2(4000 CHAR)
 
SQL> DESCRIBE "LineItemsType1666_T"
 
"LineItemsType1666_T" is NOT FINAL
Name                 Null? Type
-------------------- ----- -------------------------------
SYS_XDBPD$                 XDB.XDB$RAW_LIST_T
LineItem                   LineItem1667_COLL
 
SQL> DESCRIBE "LineItem1667_COLL"

"LineItem1667_COLL" VARRAY(2147483647) OF LineItemType1665_T
"LineItemType1665_T" is NOT FINAL
Name                Null? Type
------------------- ----- --------------------------------
SYS_XDBPD$                XDB.XDB$RAW_LIST_T
ItemNumber                NUMBER(38)
Description               VARCHAR2(256 CHAR)
Part                      PartType1664_T

Note:

By default, the names of the object types and attributes in the preceding example are system-generated.
  • Developers can use schema annotations to provide user-defined names (see "Oracle XML Schema Annotations" for details).

  • If the XML Schema does not contain the SQLName attribute, then the name is derived from the XML name.


Creating Default Tables During XML Schema Registration

As part of XML Schema registration, you can also create default tables. Default tables are most useful when XML instance documents conforming to this XML Schema are inserted through APIs that do not have any table specification, such as with FTP or HTTP. In such cases, the XML instance is inserted into the default table.

If you have given a value for attribute defaultTable, then the XMLType table is created with that name. Otherwise it gets created with an internally generated name.

Further, any text specified using the tableProps and columnProps attribute are appended to the generated CREATE TABLE statement.

Example 5-5 Default Table for Global Element PurchaseOrder

SQL> DESCRIBE "PurchaseOrder1669_TAB"

Name                        Null? Type
--------------------------- ----- -----------------------
TABLE of
  SYS.XMLTYPE(
    XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
    Element "PurchaseOrder")
  STORAGE Object-relational TYPE "PurchaseOrderType1668_T"

Generated Names are Case Sensitive

The names of SQL tables, object, and attributes generated by XML Schema registration are case sensitive. For instance, in Example 5-3, "Registering an XML Schema Using Package DBMS_XMLSCHEMA", a table called PurchaseOrder1669_TAB was created automatically during registration of the XML Schema. Since the table name was derived from the element name, PurchaseOrder, the name of the table is also mixed case. This means that you must refer to this table in SQL using a quoted identifier: "PurchaseOrder1669_TAB". Failure to do so results in an object-not-found error, such as ORA-00942: table or view does not exist.

Objects That Depend on Registered XML Schemas

The following objects are dependent on registered XML Schemas:

  • Tables or views that have an XMLType column that conforms to some element in the XML Schema.

  • XML Schemas that include or import this schema as part of their definition.

  • Cursors that reference the XML Schema name, for example, within DBMS_XMLGEN operators. Note that these are purely transient objects.

How to Obtain a List of Registered XML Schemas

To obtain a list of the XML Schemas registered with Oracle XML DB using DBMS_XMLSCHEMA.registerSchema use the following code. You can also use user_xml_schemas, all_xml_schemas, user_xml_tables, and all_xml_tables.

Example 5-6 Data Dictionary Table for Registered Schemas

SQL> DESCRIBE DBA_XML_SCHEMAS

Name         Null? Type
------------ ----- -----------------------
OWNER              VARCHAR2(30)
SCHEMA_URL         VARCHAR2(700)
LOCAL              VARCHAR2(3)
SCHEMA             XMLTYPE(XMLSchema "http://xmlns.oracle.com/xdb/XDBSchema.xsd"
                           Element "schema")
INT_OBJNAME        VARCHAR2(4000)
QUAL_SCHEMA_URL    VARCHAR2(767)

SQL> SELECT owner, local, schema_url FROM dba_xml_schemas;

OWNER   LOC   SCHEMA_URL
-----   ---   ----------------------
XDB     NO    http://xmlns.oracle.com/xdb/XDBSchema.xsd
XDB     NO    http://xmlns.oracle.com/xdb/XDBResource.xsd
XDB     NO    http://xmlns.oracle.com/xdb/acl.xsd
XDB     NO    http://xmlns.oracle.com/xdb/dav.xsd
XDB     NO    http://xmlns.oracle.com/xdb/XDBStandard.xsd
XDB     NO    http://xmlns.oracle.com/xdb/log/xdblog.xsd
XDB     NO    http://xmlns.oracle.com/xdb/log/ftplog.xsd
XDB     NO    http://xmlns.oracle.com/xdb/log/httplog.xsd
XDB     NO    http://www.w3.org/2001/xml.xsd
XDB     NO    http://xmlns.oracle.com/xdb/XDBFolderListing.xsd
XDB     NO    http://xmlns.oracle.com/xdb/stats.xsd
XDB     NO    http://xmlns.oracle.com/xdb/xdbconfig.xsd
SCOTT   YES   http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd

13 rows selected.

SQL> DESCRIBE DBA_XML_TABLES

Name         Null? Type
------------ ----- -----------------------
OWNER              VARCHAR2(30)
TABLE_NAME         VARCHAR2(30)
XMLSCHEMA          VARCHAR2(700)
SCHEMA_OWNER       VARCHAR2(30)
ELEMENT_NAME       VARCHAR2(2000)
STORAGE_TYPE       VARCHAR2(17)

SQL> SELECT table_name FROM dba_xml_tables WHERE
       XMLSCHEMA =
         'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd';

TABLE_NAME
------------------------------
PurchaseOrder1669_TAB
 
1 row selected.

Deleting Your XML Schema Using DBMS_XMLSCHEMA

You can delete your registered XML Schema by using the DBMS_XMLSCHEMA.deleteSchema procedure. When you attempt to delete an XML Schema, DBMS_XMLSCHEMA checks:

  • That the current user has the appropriate privileges (ACLs) to delete the resource corresponding to the XML Schema within Oracle XML DB repository. You can thus control which users can delete which XML Schemas by setting the appropriate ACLs on the XML Schema resources.

  • For dependents. If there are any dependents, then it raises an error and the deletion operation fails. This is referred to as the RESTRICT mode of deleting XML Schemas.

FORCE Mode

When deleting XML Schemas, if you specify the FORCE mode option, then the XML Schema deletion proceeds even if it fails the dependency check. In this mode, XML Schema deletion marks all its dependents as invalid.

The CASCADE mode option drops all generated types and default tables as part of a previous call to register XML Schema.


See Also:

Oracle XML API Reference the chapter on DBMS_XMLSCHEMA

Example 5-7 Deleting the XML Schema Using DBMS_XMLSCHEMA

The following example deletes XML Schema purchaseOrder.xsd. Then, the schema is deleted using the FORCE and CASCADE modes with DBMS_XMLSCHEMA.DELETESCHEMA:

BEGIN
  DBMS_XMLSCHEMA.deleteSchema(
    SCHEMAURL => 'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd',
    DELETE_OPTION => dbms_xmlschema.DELETE_CASCADE_FORCE);
END;
/

XML Schema-Related Methods of XMLType

Table 5-1 lists the XMLType XML Schema-related methods.

Table 5-1 XMLType API XML Schema-Related Methods

XMLType API Method Description
isSchemaBased()
Returns TRUE if the XMLType instance is based on an XML Schema, FALSE otherwise.
getSchemaURL() 
getRootElement()
getNamespace()
Returns the XML Schema URL, name of root element, and the namespace for an XML Schema-based XMLType instance.
schemaValidate()
isSchemaValid()
is SchemaValidated()
setSchemaValidated()
An XMLType instance can be validated against a registered XML Schema using the validation methods. See Chapter 8, " Transforming and Validating XMLType Data".

Local and Global XML Schemas

XML Schemas can be registered as local or global:

When you register an XML Schema, DBMS_XMLSCHEMA adds an Oracle XML DB resource corresponding to the XML Schema to the Oracle XML DB repository. The XML Schema URL determines the path name of the resource in Oracle XML DB repository (and is associated with the schemaurl parameter of registerSchema) according to the following rules:

Local XML Schema

By default, an XML Schema belongs to you after registering the XML Schema with Oracle XML DB. A reference to the XML Schema document is stored in Oracle XML DB repository, in directory. Such XML Schemas are referred to as local. In general, they are usable only by you, the owner.

In Oracle XML DB, local XML Schema resources are created under the /sys/schemas/username directory. The rest of the path name is derived from the schema URL.

Example 5-8 Registering A Local XML Schema

BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    SCHEMAURL => 'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd',
    SCHEMADOC => bfilename('XMLDIR','purchaseOrder.xsd'),
    LOCAL => TRUE,
    GENTYPES => TRUE, 
    GENTABLES => FALSE, 
    CSID => nls_charset_id('AL32UTF8'));
END;
/

If this local XML Schema is registered by user SCOTT, it is given this path name:

/sys/schemas/SCOTT/xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd

Database users need appropriate permissions and Access Control Lists (ACL) to create a resource with this path name in order to register the XML Schema as a local XML Schema.


Note:

Typically, only the owner of the XML Schema can use it to define XMLType tables, columns, or views, validate documents, and so on. However, Oracle Database supports fully qualified XML Schema URLs, which can be specified as:

http://xmlns.oracle.com/xdb/schemas/SCOTT/xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd

This extended URL can be used by privileged users to specify XML Schema belonging to other users.


Global XML Schema

In contrast to local schemas, privileged users can register an XML Schema as a global XML Schema by specifying an argument in the DBMS_XMLSCHEMA registration function.

Global schemas are visible to all users and stored under the /sys/schemas/PUBLIC/ directory in Oracle XML DB repository.


Note:

Access to this directory is controlled by Access Control Lists (ACLs) and, by default, is writable only by a DBA. You need write privileges on this directory to register global schemas.

XDBAdmin role also provides write access to this directory, assuming that it is protected by the default protected Access Control Lists (ACL). See Chapter 23, " Oracle XML DB Resource Security" for further information on privileges and for details on the XDBAdmin role.


You can register a local schema with the same URL as an existing global schema. A local schema always hides any global schema with the same name (URL).

Example 5-9 Registering A Global XML Schema

SQL> GRANT XDBADMIN TO SCOTT;

Grant succeeded.

CONNECT scott/tiger

Connected.

BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    SCHEMAURL => 'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd',
    SCHEMADOC => bfilename('XMLDIR','purchaseOrder.xsd'),
    LOCAL => FALSE,
    GENTYPES => TRUE, 
    GENTABLES => FALSE, 
    CSID => nls_charset_id('AL32UTF8'));
END;
/

If this local XML Schema is registered by user SCOTT, it is given this path name:

/sys/schemas/PUBLIC/xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd

Database users need appropriate permissions (ACLs) to create this resource in order to register the XML Schema as global.

DOM Fidelity

Document Object Model (DOM) fidelity is the concept of retaining the structure of a retrieved XML document, compared to the original XML document, for DOM traversals. DOM fidelity is needed to ensure the accuracy and integrity of XML documents stored in Oracle XML DB.

How Oracle XML DB Ensures DOM Fidelity with XML Schema

All elements and attributes declared in the XML Schema are mapped to separate attributes in the corresponding SQL object type. However, some pieces of information in XML instance documents are not represented directly by these element or attributes, such as:

  • Comments

  • Namespace declarations

  • Prefix information

To ensure the integrity and accuracy of this data, for example, when regenerating XML documents stored in the database, Oracle XML DB uses a data integrity mechanism called DOM fidelity.

DOM fidelity refers to how similar the returned and original XML documents are, particularly for purposes of DOM traversals.

DOM Fidelity and SYS_XDBPD$

In order to provide DOM fidelity, Oracle XML DB has to maintain instance-level metadata. This metadata is tracked at a type level using the system-defined binary attribute SYS_XDBPD$. This attribute is referred to as the Positional Descriptor, or PD for short. The PD attribute is intended for Oracle Corporation internal use only. You should never directly access or manipulate this column.

This positional descriptor attribute stores all pieces of information that cannot be stored in any of the other attributes, thereby ensuring the DOM fidelity of all XML documents stored in Oracle XML DB. Examples of such pieces of information include: ordering information, comments, processing instructions, namespace prefixes, and so on. This is mapped to a Positional Descriptor (PD) column.

If DOM fidelity is not required, you can suppress SYS_XDBPD$ in the XML Schema definition by setting the attribute, maintainDOM=FALSE at the type level.


Note:

The attribute SYS_XDBPD$ is omitted in many examples here for clarity. However, the attribute is always present as a Positional Descriptor (PD) column in all SQL object types generated by the XML Schema registration process.

In general however, it is not a good idea to suppress the PD attribute because the extra pieces of information, such as comments, processing instructions, and so on, could be lost if there is no PD column.


Creating XMLType Tables and Columns Based on XML Schema

Using Oracle XML DB, developers can create XMLType tables and columns that are constrained to a global element defined by a registered XML Schema. After an XMLType column has been constrained to a particular element and XML Schema it can only contain documents that are compliant with the schema definition of that element. An XMLType table column is constrained to a particular element and XML Schema by adding the appropriate XMLSCHEMA and ELEMENT clauses to the CREATE TABLE operation.

Figure 5-1 shows the syntax for creating an XMLType table:

CREATE [GLOBAL TEMPORARY] TABLE [schema.] table OF XMLType
  [(object_properties)] [XMLType XMLType_storage] [XMLSchema_spec]
  [ON COMMIT {DELETE | PRESERVE} ROWS] [OID_clause] [OID_index_clause]
  [physical_properties] [table_properties];

Figure 5-1 Creating an XMLType Table

Description of XMLType_table.gif follows
Description of the illustration XMLType_table.gif

A subset of the XPointer notation, shown in the following example, can also be used to provide a single URL containing the XML Schema location and element name. See also Chapter 4, " XMLType Operations ".

Example 5-10 Creating XML Schema-Based XMLType Tables and Columns

This example shows CREATE TABLE statements. The first creates an XMLType table, purchaseorder_as_table. The second creates a relational table, purchaseorder_as_column, with an XMLType column, xml_document. In both, the XMLType value is constrained to the PurchaseOrder element defined by the schema registered under the URL http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd.

CREATE TABLE purchaseorder_as_table OF XMLType
  XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
  ELEMENT "PurchaseOrder";

CREATE TABLE purchaseorder_as_column (id NUMBER, xml_document XMLType)
  XMLType COLUMN xml_document
  ELEMENT
    "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd#PurchaseOrder";

Note there are two ways to define the element and schema to be used. In one way, the XMLSchema and Element are specified as separator clauses. In the other way, the XMLSchema and Element are specified using the Element clause, using an XPointer notation.

The data associated with an XMLType table or column that is constrained to an XML Schema can be stored in two different ways:

  • Shred the contents of the document and store it as a set of objects. This is known as structured storage.

  • Stored the contents of the document as text, using a single LOB column. This is known as unstructured storage.

Specifying Unstructured (LOB-Based) Storage of Schema-Based XMLType

The default storage model is structured storage. To override this behavior, and store the entire XML document as a single LOB column, use the STORE AS CLOB clause.

Example 5-11 Specifying CLOB Storage for Schema-Based XMLType Tables and Columns

This example shows how to create an XMLType table and a table with an XMLType column, where the contents of the XMLType are constrained to a global element defined by a registered XML Schema, and the contents of the XMLType are stored using a single LOB column.

CREATE TABLE purchaseorder_as_table OF XMLType
  XMLType STORE AS CLOB
  XMLSCHEMA "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
  ELEMENT "PurchaseOrder";
 
CREATE TABLE purchaseorder_as_column (id NUMBER, xml_document XMLType)
  XMLType COLUMN xml_document
  STORE AS CLOB
  XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
  ELEMENT "PurchaseOrder";

Note that you can add LOB storage parameters to the STORE AS CLOB clause.

Specifying Storage Models for Structured Storage of Schema-Based XMLType

When structured storage is selected, collections (elements which have maxOccurs 1, allowing them to appear multiple times) are mapped into SQL VARRAY values. By default, the entire contents of such a VARRAY is serialized using a single LOB column. This storage model provides for optimal ingestion and retrieval of the entire document, but it has significant limitations when it is necessary to index, update, or retrieve individual members of the collection. A developer may override the way in which a VARRAY is stored, and force the members of the collection to be stored as a set of rows in a nested table. This is done by adding an explicit VARRAY STORE AS clause to the CREATE TABLE statement.

Developers can also add STORE AS clauses for any LOB columns that will be generated by the CREATE TABLE statement.

Note that the collection and the LOB column must be identified using object-relational notation. Therefore, it is important to understand the structure of the objects that are generated when a XML Schema is registered.

Example 5-12 Specifying Storage Options for Schema-Based XMLType Tables and Columns Using Structured Storage

This example shows how to create an XMLType table and a table with an XMLType column, where the contents of the XMLType are constrained to a global element defined by a registered XML Schema, and the contents of the XMLType are stored using as a set of SQL objects.

CREATE table purchaseorder_as_table 
  OF XMLType (UNIQUE ("XMLDATA"."Reference"),
              FOREIGN KEY ("XMLDATA"."User") REFERENCES hr.employees (email))
ELEMENT   
  "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd#PurchaseOrder" 
  VARRAY "XMLDATA"."Actions"."Action"
            STORE AS TABLE action_table1 ((PRIMARY KEY (nested_table_id, array_index))
                                          ORGANIZATION INDEX OVERFLOW   )
  VARRAY "XMLDATA"."LineItems"."LineItem"
            STORE AS TABLE lineitem_table1 ((PRIMARY KEY (nested_table_id, array_index))
                                            ORGANIZATION INDEX OVERFLOW)
  LOB ("XMLDATA"."Notes")
            STORE AS (TABLESPACE USERS ENABLE STORAGE IN ROW 
              STORAGE(INITIAL 4K NEXT 32K));

CREATE TABLE purchaseorder_as_column (
  id NUMBER,
  xml_document XMLType,
  UNIQUE (xml_document."XMLDATA"."Reference"),
  FOREIGN KEY (xml_document."XMLDATA"."User") REFERENCES hr.employees (email))
 
XMLType COLUMN xml_document
XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
ELEMENT "PurchaseOrder"
  VARRAY xml_document."XMLDATA"."Actions"."Action"
        STORE AS TABLE action_table2 ((PRIMARY KEY (nested_table_id, array_index))
                                          ORGANIZATION INDEX OVERFLOW)
  VARRAY xml_document."XMLDATA"."LineItems"."LineItem"
            STORE AS TABLE lineitem_table2      ((PRIMARY KEY (nested_table_id, array_index))
                                            ORGANIZATION INDEX OVERFLOW)
  LOB (xml_document."XMLDATA"."Notes")
            STORE AS (TABLESPACE USERS ENABLE STORAGE IN ROW 
              STORAGE(INITIAL 4K NEXT 32K));

The example also shows how to specify that the collection of Action elements and the collection of LineItem elements are stored as rows in nested tables, and how to specify LOB storage clauses for the LOB that will contain the content of the Notes element.


Note:

Oracle Corporation recommends the use of the thick JDBC driver especially to operate on XMLType values stored object-relationally. Note that the thin JDBC driver currently supports only XMLType values stored as CLOB values.

Specifying Relational Constraints on XMLType Tables and Columns

When structured storage is selected, typical relational constraints can be specified for elements and attributes that occur once in the XML document. Example 5-12 shows how to use object-relational notation to define a unique constraint and a foreign key constraint when creating the table.

Note that it is not possible to define constraints for XMLType tables and columns that make use of unstructured storage.

Oracle XML Schema Annotations

Oracle XML DB gives application developers the ability to influence the objects and tables that are generated by the XML Schema registration process. You use the schema annotation mechanism to do this.

Annotation involves adding extra attributes to the complexType, element, and attribute definitions that are declared by the XML Schema. The attributes used by Oracle XML DB belong to the namespace http://xmlns.oracle.com/xdb. In order to simplify the process of annotationg an XML Schema, it is recommended that a namespace prefix be declared in the root element of the XML Schema.

Common reasons for wanting to annotate an XML Schema include the following:

The most commonly used annotations are the following:

You do not have to specify values for any of these attributes. Oracle XML DB fills in appropriate values during the XML Schema registration process. However, it is recommended that you specify the names of at least the top-level SQL types so that you can reference them later.

Example 5-13 shows a partial listing of the XML Schema in Example 5-1, modified to include some of the most important XDB annotations.

Example 5-13 Using Common Schema Annotations

<xs:schema
  targetNamespace="http://xmlns.oracle.com/xdb/documentation/purchaseOrder"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xdb="http://xmlns.oracle.com/xdb"
  xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder"
  version="1.0" 
  xdb:storeVarrayAsTable="true">  <xs:element name="PurchaseOrder" type="po:PurchaseOrderType"
              xdb:defaultTable="PURCHASEORDER"/>
  <xs:complexType name="PurchaseOrderType" xdb:SQLType="PURCHASEORDER_T">
    <xs:sequence>
      <xs:element name="Reference" type="po:ReferenceType" minOccurs="1"
                  xdb:SQLName="REFERENCE"/>
      <xs:element name="Actions" type="po:ActionsType"
                  xdb:SQLName="ACTION_COLLECTION"/>
      <xs:element name="Reject" type="po:RejectionType" minOccurs="0"/>
      <xs:element name="Requestor" type="po:RequestorType"/>
      <xs:element name="User" type="po:UserType" minOccurs="1"
                  xdb:SQLName="EMAIL"/>
      <xs:element name="CostCenter" type="po:CostCenterType"/>
      <xs:element name="ShippingInstructions"
                  type="po:ShippingInstructionsType"/>
      <xs:element name="SpecialInstructions" type="po:SpecialInstructionsType"/>
      <xs:element name="LineItems" type="po:LineItemsType"
                  xdb:SQLName="LINEITEM_COLLECTION"/>
      <xs:element name="Notes" type="po:NotesType" xdb:SQLType="CLOB"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="LineItemsType" xdb:SQLType="LINEITEMS_T">
    <xs:sequence>
      <xs:element name="LineItem" type="po:LineItemType" maxOccurs="unbounded"
                  xdb:SQLCollType="LINEITEM_V" xdb:SQLName="LINEITEM_VARRAY"/>
   </xs:sequence>
  </xs:complexType>
  <xs:complexType name="LineItemType" xdb:SQLType="LINEITEM_T">
    <xs:sequence>
      <xs:element name="Description" type="po:DescriptionType"/>
      <xs:element name="Part" type="po:PartType"/>
    </xs:sequence>
    <xs:attribute name="ItemNumber" type="xs:integer"/>
  </xs:complexType>
  <xs:complexType name="PartType" xdb:SQLType="PART_T" xdb:maintainDOM="false">
    <xs:attribute name="Id">
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:minLength value="10"/>
          <xs:maxLength value="14"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:attribute>
    <xs:attribute name="Quantity" type="po:moneyType"/>
    <xs:attribute name="UnitPrice" type="po:quantityType"/>
  </xs:complexType>
</xs:schema>

The schema element includes the declaration of the xdb namespace. It also includes the annotation xdb:storeVarrayAsTable="true". This will force all collections within the XML Schema to be managed using nested tables.

The definition of the global element PurchaseOrder includes a defaultTable annotation that specifies that the name of the default table associated with this element is PURCHASEORDER.

The global complexType PurchaseOrderType includes a SQLType annotation that specifies that the name of the generated SQL object type will be PURCHASEORDER_T. Within the definition of this type, the following annotations are used:

  • The element Reference includes a SQLName annotation that ensures that the name of the SQL attribute corresponding to the Reference element will be named REFERENCE.

  • The element Actions includes a SQLName annotation that ensures that the name of the SQL attribute corresponding to the Actions element will be ACTION_COLLECTION.

  • The element USER includes a SQLName annotation that ensures that the name of the SQL attribute corresponding to the User element will be EMAIL.

  • The element LineItems includes a SQLName annotation that ensures that the name of the SQL attribute corresponding to the LineItems element will be LINEITEM_COLLECTION.

  • The element Notes includes a SQLType annotation that ensures that the datatype of the SQL attribute corresponding to the Notes element will be CLOB.

The global complexType LineItemsType includes a SQLType annotation that specifies that the names of generated SQL object type will be LINEITEMS_T. Within the definition of this type, the following annotations are used:

  • The element LineItem includes a SQLName annotation that ensures that the datatype of the SQL attribute corresponding to the LineItems element will be LINEITEM_VARRAY, and a SQLCollName annotation that ensures that the name of the SQL object type that manages the collection will be LINEITEM_V.

The global complexType LineItemType includes a SQLType annotation that specifies that the names of generated SQL object type will be LINEITEM_T.

The global complexType PartType includes a SQLType annotation that specifies that the names of generated SQL object type will be PART_T. It also includes the annotation xdb:maintainDOM="false", specifying that there is no need for Oracle XML DB to maintain DOM fidelity for elements based on this type.

Example 5-14 Results of Registering an Annotated XML Schema

The following code shows some of the tables and objects created when the annotated XML Schema is registered.

BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    SCHEMAURL => 'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd',
    SCHEMADOC => bfilename('XMLDIR','purchaseOrder.Annotated.xsd'),
    LOCAL => TRUE,
    GENTYPES => TRUE,
    GENTABLES => TRUE,
    CSID => nls_charset_id('AL32UTF8'));
END;
/
 
SQL> SELECT TABLE_NAME, XMLSCHEMA, ELEMENT_NAME FROM USER_XML_TABLES;
 
TABLE_NAME     XMLSCHEMA                             ELEMENT_NAME
-------------  -----------------------------------   -------------
PURCHASEORDER  http://xmlns.oracle.com/xdb/documen   PurchaseOrder
               tation/purchaseOrder.xsd              
 
1 row selected.
 
SQL> DESCRIBE PURCHASEORDER

Name                            Null? Type
------------------------------  ----- -----------------
TABLE of SYS.XMLTYPE(XMLSchema
 "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
 ELEMENT "PurchaseOrder") STORAGE Object-relational TYPE "PURCHASEORDER_T"
 
SQL> DESCRIBE PURCHASEORDER_T

PURCHASEORDER_T is NOT FINAL
Name                 Null? Type
-------------------- ----- --------------------------
SYS_XDBPD$                 XDB.XDB$RAW_LIST_T
REFERENCE                  VARCHAR2(30 CHAR)
ACTION_COLLECTION          ACTIONS_T
Reject                     REJECTION_T
Requestor                  VARCHAR2(128 CHAR)
EMAIL                      VARCHAR2(10 CHAR)
CostCenter                 VARCHAR2(4 CHAR)
ShippingInstructions       SHIPPING_INSTRUCTIONS_T
SpecialInstructions        VARCHAR2(2048 CHAR)
LINEITEM_COLLECTION        LINEITEMS_T
Notes                      CLOB

SQL> DESCRIBE LINEITEMS_T
LINEITEMS_T is NOT FINAL
Name                 Null? Type
-------------------- ----- --------------------------
SYS_XDBPD$                 XDB.XDB$RAW_LIST_T
LINEITEM_VARRAY            LINEITEM_V

SQL> DESCRIBE LINEITEM_V

LINEITEM_V VARRAY(2147483647) OF LINEITEM_T
LINEITEM_T is NOT FINAL
Name                 Null? Type
-------------------- ----- --------------------------
SYS_XDBPD$                 XDB.XDB$RAW_LIST_T
ItemNumber                 NUMBER(38)
Description                VARCHAR2(256 CHAR)
Part                       PART_T

SQL> DESCRIBE PART_T
 
PART_T is NOT FINAL
Name                 Null? Type
-------------------- ----- --------------------------
Id                         VARCHAR2(14 CHAR)
Quantity                   NUMBER(12,2)
UnitPrice                  NUMBER(8,4)

SQL> SELECT TABLE_NAME, PARENT_TABLE_COLUMN FROM USER_NESTED_TABLES
       WHERE PARENT_TABLE_NAME = 'PURCHASEORDER';

TABLE_NAME                       PARENT_TABLE_COLUMN
----------                       -----------------------   
SYS_NTNOHV+tfSTRaDTA9FETvBJw==   "XMLDATA"."LINEITEM_COLLECTION"."LINEITEM_VARRAY"
SYS_NTV4bNVqQ1S4WdCIvBK5qjZA==   "XMLDATA"."ACTION_COLLECTION"."ACTION_VARRAY"
 
2 rows selected.

A table called PURCHASEORDER has been created.

Types called PURCHASEORDER_T, LINEITEMS_T, LINEITEM_V, LINEITEM_T, and PART_T have been created. The attributes defined by these types are named according to supplied the SQLName annotations.

The Notes attribute defined by PURCHASEORDER_T has a datatype of CLOB.

PART_T does not include a Positional Descriptor attribute.

Nested tables have been created to manage the collections of LineItem and Action elements.

Table 5-2 lists Oracle XML DB annotations that you can specify in element and attribute declarations.

Table 5-2 Annotations You Can Specify in Elements

Attribute Values Default Description

SQLName

Any SQL identifier Element name Specifies the name of the attribute within the SQL object that maps to this XML element.

SQLType

Any SQL type name Name generated from element name Specifies the name of the SQL type corresponding to this XML element declaration.

SQLCollType

Any SQL collection type name Name generated from element name Specifies the name of the SQL collection type corresponding to this XML element that has maxOccurs>1.

SQLSchema

Any SQL username User registering XML Schema Name of database user owning the type specified by SQLType.

SQLCollSchema

Any SQL username User registering XML Schema Name of database user owning the type specified by SQLCollType.

maintainOrder

true | false true If true, the collection is mapped to a VARRAY. If false, the collection is mapped to a NESTED TABLE.

SQLInline

true | false true If true this element is stored inline as an embedded attribute (or a collection if maxOccurs 1). If false, a REF value is stored (or a collection of REF values, if maxOccurs>1). This attribute is forced to false in certain situations (like cyclic references) where SQL will not support inlining.

maintainDOM

true | false true If true, instances of this element are stored such that they retain DOM fidelity on output. This implies that all comments, processing instructions, namespace declarations, and so on are retained in addition to the ordering of elements. If false, the output need not be guaranteed to have the same DOM action as the input.

columnProps

Any valid column storage clause NULL Specifies the column storage clause that is inserted into the default CREATE TABLE statement. It is useful mainly for elements that get mapped to tables, namely top-level element declarations and out-of-line element declarations.

tableProps

Any valid table storage clause NULL Specifies the TABLE storage clause that is appended to the default CREATE TABLE statement. This is meaningful mainly for global and out-of-line elements.

defaultTable

Any table name Based on element name. Specifies the name of the table into which XML instances of this schema should be stored. This is most useful in cases when the XML is being inserted from APIs where table name is not specified, for example, FTP and HTTP.

Table 5-3 Annotations You Can Specify in Elements Declaring Global complexTypes

Attribute Values Default Description

SQLType

Any SQL type name Name generated from element name Specifies the name of the SQL type corresponding to this XML element declaration.

SQLSchema

Any SQL username User registering XML Schema Name of database user owning the type specified by SQLType.

maintainDOM

true | false true If true, instances of this element are stored such that they retain DOM fidelity on output. This implies that all comments, processing instructions, namespace declarations, and so on, are retained in addition to the ordering of elements. If false, the output need not be guaranteed to have the same DOM action as the input.

Table 5-4 Annotations You Can Specify in XML Schema Declarations

Attribute Values Default Description

mapUnbounded StringToLob

true | false false If true, unbounded strings are mapped to CLOB by default. Similarly, unbounded binary data gets mapped to a Binary Large Object (BLOB), by default. If false, unbounded strings are mapped to VARCHAR2(4000) and unbounded binary components are mapped to RAW(2000).

StoreVarrayAsTable

true | false false If true, the VARRAY is stored as a table (OCT). If false, the VARRAY is stored in a LOB.

Querying a Registered XML Schema to Obtain Annotations

The registered version of an XML Schema will contain a full set of XDB annotations. As was shown in Example 5-8, and Example 5-9, the location of the registered XML Schema depends on whether the schema is a local or global schema.

This document can be queried to find out the values of the annotations that were supplied by the user, or added by the schema registration process. For instance, the following query shows the set of global complexType definitions declared by the XMLSchema and the corresponding SQL objects types:

Example 5-15 Querying Metadata from a Registered XML Schema

SELECT extractValue(value(ct),
                            '/xs:complexType/@name',
                            'xmlns:xs="http://www.w3.org/2001/XMLSchema"
                             xmlns:xdb="http://xmlns.oracle.com/xdb"')
       XMLSCHEMA_TYPE_NAME,
       extractValue(value(ct),
                            '/xs:complexType/@xdb:SQLType',
                            'xmlns:xs="http://www.w3.org/2001/XMLSchema"
                             xmlns:xdb="http://xmlns.oracle.com/xdb"')
       SQL_TYPE_NAME
  FROM resource_view,
       table(
         xmlsequence(
           extract(
             res,
             '/r:Resource/r:Contents/xs:schema/xs:complexType',
                     'xmlns:r="http://xmlns.oracle.com/xdb/XDBResource.xsd"
                      xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder"
                      xmlns:xs="http://www.w3.org/2001/XMLSchema"
                      xmlns:xdb="http://xmlns.oracle.com/xdb"'))) ct
  WHERE
    equals_path(
      res,
     '/sys/schemas/SCOTT/xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd')
    =1;

XMLSCHEMA_TYPE_NAME              SQL_TYPE_NAME
-------------------------------- --------------------------------
PurchaseOrderType                PURCHASEORDER_T
LineItemsType                    LINEITEMS_T
LineItemType                     LINEITEM_T
PartType                         PART_T
ActionsType                      ACTIONS_T
RejectionType                    REJECTION_T
ShippingInstructionsType         SHIPPING_INSTRUCTIONS_T

7 rows selected.

SQL Mapping Is Specified in the XML Schema During Registration

Information regarding the SQL mapping is stored in the XML Schema document. The registration process generates the SQL types, as described in "Mapping of Types Using DBMS_XMLSCHEMA" and adds annotations to the XML Schema document to store the mapping information. Annotations are in the form of new attributes.

Example 5-16 Capturing SQL Mapping Using SQLType and SQLName Attributes

The following XML Schema definition shows how SQL mapping information is captured using SQLType and SQLName attributes:

DECLARE
  doc VARCHAR2(3000) := 
   '<schema
     targetNamespace="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
     xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
     xmlns:xdb="http://xmlns.oracle.com/xdb"
     xmlns="http://www.w3.org/2001/XMLSchema">
      <complexType name="PurchaseOrderType">
        <sequence>
          <element name="PONum" type="decimal" xdb:SQLName="PONUM"
                   xdb:SQLType="NUMBER"/>
          <element name="Company" xdb:SQLName="COMPANY" xdb:SQLType="VARCHAR2">
            <simpleType>
              <restriction base="string">
                <maxLength value="100"/>
              </restriction>
            </simpleType>
          </element>
          <element name="Item"  xdb:SQLName="ITEM" xdb:SQLType="ITEM_T"
                   maxOccurs="1000">
            <complexType>
              <sequence>
                <element name="Part"  xdb:SQLName="PART" xdb:SQLType="VARCHAR2">
                  <simpleType>
                    <restriction base="string">
                      <maxLength value="1000"/>
                    </restriction>
                  </simpleType>
                </element>
                <element name="Price" type="float"  xdb:SQLName="PRICE"
                         xdb:SQLType="NUMBER"/>
              </sequence>
            </complexType>
          </element>
        </sequence>
      </complexType>
      <element name="PurchaseOrder" type="po:PurchaseOrderType"/>
    </schema>';
BEGIN
   DBMS_XMLSCHEMA.registerSchema(
     'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd', doc);
END;

Figure 5-2 shows how Oracle XML DB creates XML Schema-based XMLType tables using an XML document and mapping specified in an XML Schema.

Figure 5-2 How Oracle XML DB Maps XML Schema-Based XMLType Tables

Description of adxdb025.gif follows
Description of the illustration adxdb025.gif

An XMLType table is first created and depending on how the storage is specified in the XML Schema, the XML document is mapped and stored either as a CLOB in one XMLType column, or stored object-relationally and spread out across several columns in the table.

Mapping of Types Using DBMS_XMLSCHEMA

Use DBMS_XMLSCHEMA to set the mapping of type information for attributes and elements.

Setting Attribute Mapping Type Information

An attribute declaration can have its type specified in terms of one of the following:

  • Primitive type

  • Global simpleType, declared within this XML Schema or in an external XML Schema

  • Reference to global attribute (ref=".."), declared within this XML Schema or in an external XML Schema

  • Local simpleType

In all cases, the SQL type and associated information (length and precision) as well as the memory mapping information, are derived from the simpleType on which the attribute is based.

Overriding the SQLType Value in XML Schema When Declaring Attributes

You can explicitly specify a SQLType value in the input XML Schema document. In this case, your specified type is validated. This allows for the following specific forms of overrides:

  • If the default type is a STRING, then you can override it with any of the following: CHAR, VARCHAR, or CLOB.

  • If the default type is RAW, then you can override it with RAW or BLOB.

Setting Element Mapping Type Information

An element declaration can specify its type in terms of one of the following:

  • Any of the ways for specifying type for an attribute declaration. See "Setting Attribute Mapping Type Information" .

  • Global complexType, specified within this XML Schema document or in an external XML Schema.

  • Reference to a global element (ref="..."), which could itself be within this XML Schema document or in an external XML Schema.

  • Local complexType.

Overriding the SQLType Value in XML Schema When Declaring Elements

An element based on a complexType is, by default, mapped to an object type containing attributes corresponding to each of the sub-elements and attributes. However, you can override this mapping by explicitly specifying a value for SQLType attribute in the input XML Schema. The following values for SQLType are permitted in this case:

  • VARCHAR2

  • RAW

  • CLOB

  • BLOB

These represent storage of the XML in a text or unexploded form in the database.

For example, to override the SQLType from VARCHAR2 to CLOB declare the XDB namespace as follows:

xmlns:xdb"http://xmlns.oracle.com/xdb"

and then use xdb:SQLType="CLOB".

The following special cases are handled:

  • If a cycle is detected, as part of processing the complexTypes used to declare elements and elements declared within the complexType, then the SQLInline attribute is forced to be "false" and the correct SQL mapping is set to REF XMLType.

  • If maxOccurs > 1, a VARRAY type may be created.

    • If SQLInline ="true", then a varray type is created whose element type is the SQL type previously determined.

      • Cardinality of the VARRAY is determined based on the value of maxOccurs attribute.

      • The name of the VARRAY type is either explicitly specified by the user using SQLCollType attribute or obtained by mangling the element name.

    • If SQLInline="false", then the SQL type is set to XDB.XDB$XMLTYPE_REF_LIST_T, a predefined type representing an array of REF values to XMLType.

  • If the element is a global element, or if SQLInline="false", then the system creates a default table. The name of the default table is specified by you or derived by mangling the element name.


See Also:

Chapter 6, " XML Schema Storage and Query: Advanced Topics" for more information about mapping simpleType values and complexType values to SQL.

Mapping simpleTypes to SQL

This section describes how XML Schema definitions map XML Schema simpleType to SQL object types. Figure 5-3 shows an example of this.

Table 5-5 through Table 5-8 list the default mapping of XML Schema simpleType to SQL, as specified in the XML Schema definition. For example:

Figure 5-3 Mapping simpleType: XML Strings to SQL VARCHAR2 or CLOBs

Description of adxdb038.gif follows
Description of the illustration adxdb038.gif

Table 5-5 Mapping XML String Datatypes to SQL

XML Primitive Type Length or MaxLength Facet Default Mapping Compatible Datatype
string n VARCHAR2(n) if n < 4000, else VARCHAR2(4000) CHAR, CLOB
string -- VARCHAR2(4000) if mapUnboundedStringToLob="false", CLOB CHAR, CLOB

Table 5-6 Mapping XML Binary Datatypes (hexBinary/base64Binary) to SQL

XML Primitive Type Length or MaxLength Facet Default Mapping Compatible Datatype
hexBinary, base64Binary n RAW(n) if n < 2000, else RAW(2000) RAW, BLOB
hexBinary, base64Binary - RAW(2000) if mapUnboundedStringToLob="false", BLOB RAW, BLOB

Table 5-7 Default Mapping of Numeric XML Primitive Types to SQL

XML Simple Type Default Oracle DataType totalDigits (m), fractionDigits(n) Specified Compatible Datatypes
float NUMBER NUMBER(m,n) FLOAT, DOUBLE, BINARY_FLOAT
double NUMBER NUMBER(m,n) FLOAT, DOUBLE, BINARY_DOUBLE
decimal NUMBER NUMBER(m,n) FLOAT, DOUBLE
integer NUMBER NUMBER(m,n) NUMBER
nonNegativeInteger NUMBER NUMBER(m,n) NUMBER
positiveInteger NUMBER NUMBER(m,n) NUMBER
nonPositiveInteger NUMBER NUMBER(m,n) NUMBER
negativeInteger NUMBER NUMBER(m,n) NUMBER
long NUMBER(20) NUMBER(m,n) NUMBER
unsignedLong NUMBER(20) NUMBER(m,n) NUMBER
int NUMBER(10) NUMBER(m,n) NUMBER
unsignedInt NUMBER(10) NUMBER(m,n) NUMBER
short NUMBER(5) NUMBER(m,n) NUMBER
unsignedShort NUMBER(5) NUMBER(m,n) NUMBER
byte NUMBER(3) NUMBER(m,n) NUMBER
unsignedByte NUMBER(3) NUMBER(m,n) NUMBER

Table 5-8 Mapping XML Date Datatypes to SQL

XML Primitive Type Default Mapping Compatible Datatypes
datetime TIMESTAMP TIMESTAMP WITH TIME ZONE, DATE
time TIMESTAMP TIMESTAMP WITH TIME ZONE, DATE
date DATE TIMESTAMP WITH TIME ZONE
gDay DATE TIMESTAMP WITH TIME ZONE
gMonth DATE TIMESTAMP WITH TIME ZONE
gYear DATE TIMESTAMP WITH TIME ZONE
gYearMonth DATE TIMESTAMP WITH TIME ZONE
gMonthDay DATE TIMESTAMP WITH TIME ZONE
duration VARCHAR2(4000) none

Table 5-9 Default Mapping of Other XML Primitive Datatypes to SQL

XML Simple Type Default Oracle DataType Compatible Datatypes
Boolean RAW(1) VARCHAR2
Language(string) VARCHAR2(4000) CLOB, CHAR
NMTOKEN(string) VARCHAR2(4000) CLOB, CHAR
NMTOKENS(string) VARCHAR2(4000) CLOB, CHAR
Name(string) VARCHAR2(4000) CLOB, CHAR
NCName(string) VARCHAR2(4000) CLOB, CHAR
ID VARCHAR2(4000) CLOB, CHAR
IDREF VARCHAR2(4000) CLOB, CHAR
IDREFS VARCHAR2(4000) CLOB, CHAR
ENTITY VARCHAR2(4000) CLOB, CHAR
ENTITIES VARCHAR2(4000) CLOB, CHAR
NOTATION VARCHAR2(4000) CLOB, CHAR
anyURI VARCHAR2(4000) CLOB, CHAR
anyType VARCHAR2(4000) CLOB, CHAR
anySimpleType VARCHAR2(4000) CLOB, CHAR
QName XDB.XDB$QNAME --

simpleType: Mapping XML Strings to SQL VARCHAR2 Versus CLOBs

If the XML Schema specifies the datatype to be string with a maxLength value of less than 4000, then it is mapped to a VARCHAR2 attribute of the specified length. However, if maxLength is not specified in the XML Schema, then it can only be mapped to a LOB. This is sub-optimal when most of the string values are small and only a small fraction of them are large enough to need a LOB.

Working with Time Zones

The following XML Schema types allow for an optional time-zone indicator as part of their literal values.

  • xsd:dateTime

  • xsd:time

  • xsd:date

  • xsd:gYear

  • xsd:gMonth

  • xsd:gDay

  • xsd:gYearMonth

  • xsd:gMonthDay

By default, the schema registration maps xsd:dateTime and xsd:time to SQL TIMESTAMP and all the other datatypes to SQL DATE. The SQL TIMESTAMP and DATE types do not permit the time-zone indicator.

However, if the application needs to work with time-zone indicators, then the schema should explicitly specify the SQL type to be TIMESTAMP WITH TIME ZONE, using the xdb:SQLType attribute. This ensures that values containing time-zone indicators can be stored and retrieved correctly.

Example:

<element name="dob" type="xsd:dateTime" 
  xdb:SQLType="TIMESTAMP WITH TIME ZONE"/>

<attribute name="endofquarter" type="xsd:gMonthDay" 
  xdb:SQLType="TIMESTAMP WITH TIME ZONE"/>

Note: Using trailing Z to indicate UTC time zone.

XML Schema allows the time-zone component to be specified as Z to indicate UTC time zone. When a value with a trailing Z is stored in a TIMESTAMP WITH TIME ZONE column, the time zone is actually stored as +00:00. Thus, the retrieved value contains the trailing +00:00 and not the original Z.

Example: If the value in the input XML document is 1973-02-12T13:44:32Z, the output will look like 1973-02-12T13:44:32.000000+00:00.

Mapping complexTypes to SQL

Using XML Schema, a complexType is mapped to a SQL object type as follows:

If the XML element is declared with attribute maxOccurs 1, then it is mapped to a collection attribute in SQL. The collection could be a VARRAY value (default) or nested table if the maintainOrder attribute is set to false. Further, the default storage of the VARRAY value is in Ordered Collections in Tables (OCTs) instead of LOBs. You can choose LOB storage by setting the storeAsLob attribute to true.

Specifying Attributes in a complexType XML Schema Declaration

When you have an element based on a global complexType, the SQLType and SQLSchema attributes must be specified for the complexType declaration. In addition you can optionally include the same SQLType and SQLSchema attributes within the element declaration.

The reason is that if you do not specify the SQLType for the global complexType, Oracle XML DB creates a SQLType with an internally generated name. The elements that reference this global type cannot then have a different value for SQLType. In other words, the following code is fine:

<xsd:complexType name="PURCHASEORDERLINEITEM_TYPEType">
  <xsd:sequence>
    <xsd:element name="LineNo" type="xsd:double" 
                 xdb:SQLName="LineNo" xdb:SQLType="NUMBER"/>
    <xsd:element name="Decription" type="xsd:string"
                 xdb:SQLName="Decription" xdb:SQLType="VARCHAR2"/>
    <xsd:element name="Part" type="PURCHASEORDERPART_TYPEType"
                 xdb:SQLName="Part" />
  </xsd:sequence>
</xsd:complexType>
  <xsd:complexType name="PURCHASEORDERPART_TYPEType" xdb:SQLSchema="XMLUSER"
                   xdb:SQLType="PURCHASEORDERPART_TYPE">
     <xsd:sequence>
       <xsd:element name="Id" type="xsd:string" 
                    xdb:SQLName="Id"xdb:SQLType="VARCHAR2"/>
       <xsd:element name="Quantity" type="xsd:double"
                    xdb:SQLName="Quantity" xdb:SQLType="NUMBER"/>
       <xsd:element name="cost" type="xsd:double"
                    xdb:SQLName="cost"xdb:SQLType="NUMBER"/>
     </xsd:sequence>
   </xsd:complexType>

The following is also fine:

<xsd:complexType name="PURCHASEORDERLINEITEM_TYPEType">
  <xsd:sequence>
    <xsd:element name="LineNo" type="xsd:double" 
                 xdb:SQLName="LineNo" xdb:SQLType="NUMBER"/>
    <xsd:element name="Decription" type="xsd:string"
                 xdb:SQLName="Decription" xdb:SQLType="VARCHAR2"/>
    <xsd:element name="Part" type="PURCHASEORDERPART_TYPEType"
                 xdb:SQLName="Part" xdb:SQLSchema="XMLUSER"
                 xdb:SQLType="PURCHASEORDERPART_TYPE" />
  </xsd:sequence>
</xsd:complexType>

You Must Specify a Namespace With Remote XMLType Functions

When using XMLType functions such as extract() and existsNode() remotely for XML Schema-based views or tables, you must specify the namespace completely.


NVARCHAR and NCHAR SQLType Values are Not Supported

Oracle XML DB does not support NVARCHAR or NCHAR as a SQLType when registering an XML Schema. In other words in the XML Schema .xsd file you cannot specify that an element should be of type NVARCHAR or NCHAR. Also, if you provide your own type you should not use these datatypes.

XPath Rewrite with XML Schema-Based Structured Storage

This section describes XPath rewrite support in Oracle XML DB and how to use it for XML Schema based structured storage.

What Is XPath Rewrite?

When the XMLType is stored in structured storage (object-relationally) using an XML Schema and queries using XPath are used, they can potentially be rewritten directly to the underlying object-relational columns. This rewrite of queries can also potentially happen when queries using XPath are issued on certain non-schema-based XMLType views.

This enables the use of B*Tree or other indexes, if present on the column, to be used in query evaluation by the Optimizer. This XPath rewrite mechanism is used for XPaths in SQL functions such as existsNode(), extract(), extractValue(), and updateXML(). This enables the XPath to be evaluated against the XML document without having to ever construct the XML document in memory.


Note:

XPath queries that get rewritten are a subset of the set of supported XPath queries. As far as possible, queries should be written so that the XPath rewrite advantages are realized.

Example 5-17 XPath Rewrite

For example a query such as:

SELECT VALUE(p) FROM MyPOs p
     WHERE extractValue(value(p),'/PurchaseOrder/Company') = 'Oracle';

is trying to get the value of the Company element and compare it with the literal 'Oracle'. Because the MyPOs table has been created with XML Schema-based structured storage, the extractValue operator gets rewritten to the underlying relational column that stores the company information for the purchaseOrder.

Thus the preceding query is rewritten to the following:

SELECT VALUE(p) FROM MyPOs p WHERE p.xmldata.Company = 'Oracle';

Note:

XMLDATA is a pseudo-attribute of XMLType that enables direct access to the underlying object column. See Chapter 4, " XMLType Operations ", under "Changing the Storage Options on an XMLType Column Using XMLData".

If there was a regular index created on the Company column, such as:

CREATE INDEX company_index ON MyPos e
      (extractvalue(value(e),'/PurchaseOrder/Company'));

then the preceding query would use the index for its evaluation.

XPath rewrite happens for XML Schema-based tables and both schema-based and non-schema based views. In this chapter we consider examples related to schema-based tables.


See Also:

Chapter 3, " Using Oracle XML DB", "Understanding and Optimizing XPath Rewrite", for additional examples of rewrite over schema-based and non-schema based views

When Does XPath Rewrite Occur?

XPath rewrite happens for the following SQL functions:

  • extract

  • existsNode

  • extractValue

  • updateXML

  • XMLSequence

The rewrite happens when these SQL functions are present in any expression in a query, DML, or DDL statement. For example, you can use extractValue() to create indexes on the underlying relational columns.

Example 5-18 SELECT Statement and XPath Rewrites

This example gets the existing purchase orders:

SELECT extractValue(value(x), '/PurchaseOrder/Company')
  FROM MYPOs x
  WHERE existsNode(value(x), '/PurchaseOrder/Item[1]/Part') = 1;

Here are some examples of statements that get rewritten to use underlying columns:

Example 5-19 DML Statement and XPath Rewrites

This example deletes all PurchaseOrders where the Company is not Oracle:

DELETE FROM MYPOs x
  WHERE extractValue(value(x),'/PurchaseOrder/Company') = 'Oracle Corp';

Example 5-20 CREATE INDEX Statement and XPath Rewrites

This example creates an index on the Company column, because this is stored object relationally and the XPath rewrite happens, a regular index on the underlying relational column will be created:

CREATE INDEX company_index ON MyPos e
      (extractValue(value(e),'/PurchaseOrder/Company'));

In this case, if the rewrite of the SQL functions results in a simple relational column, then the index is turned into a B*Tree or a domain index on the column, rather than a function-based index.

What XPath Expressions Are Rewritten?

The rewrite of XPath expressions happen if all of the following hold true:

  • The XML function or method is rewritable.

    The SQL functions extract, existsNode, extractValue, updateXML and XMLSequence get rewritten. Other than the existsNode() method, none of the methods of XMLType get rewritten. You can however use the SQL function equivalents instead.

  • The XPath construct is rewritable

    XPath constructs such as simple expressions, wildcards, and descendent axes get rewritten. The XPath may select attributes, elements or text nodes. Predicates also get rewritten to SQL predicates. Expressions involving parent axes, sibling axis, and so on are not rewritten.

  • The XMLSchema constructs for these paths are rewritable.

    XMLSchema constructs such as complex types, enumerated values, lists, inherited types, and substitution groups are rewritten. Constructs such as recursive type definitions are not rewritten.

  • The storage structure chosen during the schema registration is rewritable.

    Storage using the object-relational mechanism is rewritten. Storage of complex types using CLOBs are not rewritten

Table 5-10 lists the kinds of XPath expressions that can be translated into underlying SQL queries in this release.

Table 5-10 Sample List of XPath Expressions for Translation to Underlying SQL constructs

XPath Expression for Translation Description
Simple XPath expressions:

/PurchaseOrder/@PurchaseDate

/PurchaseOrder/Company

Involves traversals over object type attributes only, where the attributes are simple scalar or object types themselves. The only axes supported are the child and the attribute axes.
Collection traversal expressions:

/PurchaseOrder/Item/Part

Involves traversal of collection expressions. The only axes supported are child and attribute axes. Collection traversal is not supported if the SQL operator is used during CREATE INDEX or updateXML().
Predicates:

[Company="Oracle"]

Predicates in the XPath are rewritten into SQL predicates. Predicates are not rewritten for updateXML()
List index:

lineitem[1]

Indexes are rewritten to access the nth item in a collection. These are not rewritten for updateXML().
Wildcard traversals:

/PurchaseOrder/*/Part

If the wildcard can be translated to a unique XPath (for example, /PurchaseOrder/Item/Part), then it gets rewritten, provided it is not the last entry in the path expression.
Descendent axis:

/PurchaseOrder//Part

Similar to the wildcard expression. The descendent axis gets rewritten, if it can be mapped to a unique XPath expression and the subsequent element is not involved in a recursive type definition.
Oracle provided extension functions and some XPath functions

not, floor, ceiling, substring, string-length, translate

ora:contains

Any function from the Oracle XML DB namespace (http://xmlns.oracle.com/xdb) gets rewritten into the underlying SQL function. Some XPath functions also get rewritten.
String bind variables inside predicates

'/PurchaseOrder[@Id="'|| :1 || '"]'

XPath expressions using SQL bind variables are also rewritten provided the bind variable occurs between the concat (||) operators and is inside the double quotes in XPath.
Un-nest operations using XMLSequence

TABLE(XMLSequence(extract(...)))

XMLSequence combined with Extract, when used in a TABLE clause is rewritten to use the underlying nested table structures.

Common XPath Constructs Supported in XPath Rewrite

The following are some of the XPath constructs that get rewritten. This is not an exhaustive list and only illustrates some of the common forms of XPath expressions that get rewritten.

  • Simple XPath traversals

  • Predicates and index accesses

    Oracle provided extension functions on scalar values.

    SQL Bind variables.

  • Descendant axes (XML Schema-based only): Rewrites over descendant axis (//) are supported if:

    • There is at least one XPath child or attribute access following the //

    • Only one descendant of the children can potentially match the XPath child or attribute name following the //. If the schema indicates that multiple descendants children can potentially match, and there is no unique path the // can be expanded to, then no rewrite is done.

    • None of the descendants have an element of type xsi:anyType

    • There is no substitution group that has the same element name at any descendant.

  • Wildcards (XML Schema-based only): Rewrites over wildcard axis (/*) are supported if:

    • There is at least one XPath child or attribute access following the /*

    • Only one of the grandchildren can potentially match the XPath child or attribute name following the /*. If the schema indicates that multiple grandchildren can potentially match, and there is no unique path the /* can be expanded to, then no rewrite is done.

    • None of the children or grandchildren of the node before the /* have an element of type xsi:anyType

    • There is no substitution group that has the same element name for any child of the node before the /*.

Unsupported XPath Constructs in XPath Rewrite

The following XPath constructs do not get rewritten:

  • XPath Functions other than the ones listed earlier. Also the listed functions are rewritten only if the input is a scalar element.

  • XPath Variable references.

  • All axis other than child and attribute axis.

  • Recursive type definitions with descendent axis.

  • UNION operations.

Common XMLSchema constructs supported in XPath Rewrite

In addition to the standard XML Schema constructs such as complex types, sequences, and so on, the following additional XML Schema constructs are also supported. This is not an exhaustive list and seeks to illustrate the common schema constructs that get rewritten.

  • Collections of scalar values where the scalar values are used in predicates.

  • Simple type extensions containing attributes.

  • Enumerated simple types.

  • Boolean simple type.

  • Inheritance of complex types.

  • Substitution groups.

Unsupported XML Schema Constructs in XPath Rewrite

The following XML Schema constructs are not supported. This means that if the XPath expression includes nodes with the following XML Schema construct then the entire expression will not get rewritten:

  • XPath expressions accessing children of elements containing open content, namely any content. When nodes contain any content, then the expression cannot be rewritten, except when the any targets a namespace other than the namespace specified in the XPath. any attributes are handled in a similar way.

  • Non-coercible datatype operations, such as a Boolean added with a number

Common storage constructs supported in XPath Rewrite

All rewritable XPath expressions over object-relational storage get rewritten. In addition to that, the following storage constructs are also supported for rewrite.

Simple numeric types mapped to SQL RAW datatype.

Various date and time types mapped to the SQL TIMESTAMP_WITH_TZ datatype.

Collections stored inline, out-of-line, as OCTs and nested tables.

XML functions over schema-based and non-schema based XMLType views and SQL/XML views also get rewritten. See the views chapter to get detailed information regarding the rewrite.

Unsupported Storage Constructs in XPath Rewrite

The following XML Schema storage constructs are not supported. This means that if the XPath expression includes nodes with the following storage construct then the entire expression will not get rewritten:

  • CLOB storage: If the XML Schema maps part of the element definitions to a SQL CLOB value, then XPath expressions traversing such elements are not supported

Is there a difference in XPath logic with rewrite?

For the most part, there is no difference between rewritten XPath queries and functionally evaluated ones. However, since XPath rewrite uses XML Schema information to turn XPath predicates into SQL predicates, comparison of non-numeric entities are different.

In XPath 1.0, the comparison operators, >, <, >=, and <= use only numeric comparison. The two sides of the operator are turned into numeric values before comparison. If either of them fail to be a numeric value, the comparison returns FALSE.

For instance, if I have a schema element such as,

<element name="ShipDate" type="xs:date"   xdb:SQLType="DATE"/>

An XPath predicate such as [ShipDate < '2003-02-01'] will always evaluate to false with functional evaluation, since the string value '2003-02-01' cannot be converted to a numeric quantity. With XPath rewrite, however, this gets translated to a SQL date comparison and will evaluate to true or false depending on the value of ShipDate.

Similarly if you have a collection value compared with another collection value, the XPath 1.0 semantics dictate that the values have to be converted to a string and then compared. With Query Rewrite, the comparison will use the SQL datatype comparison rules.

To suppress this behavior, you can turn off rewrite either using query hints or session level events.

How are the XPaths Rewritten?

The following sections use the same purchaseorder XML Schema explained earlier in the chapter to explain how the functions get rewritten.

Example 5-21 Registering Example Schema

Consider the following purchaseorder XML Schema:

DECLARE
  doc VARCHAR2(2000) := 
   '<schema  
     targetNamespace="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
     xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd" 
     xmlns="http://www.w3.org/2001/XMLSchema"   
     elementFormDefault="qualified">
      <complexType name="PurchaseOrderType">
        <sequence>
          <element name="PONum" type="decimal"/>
          <element name="Company">
            <simpleType>
              <restriction base="string">
                <maxLength value="100"/>
              </restriction>
            </simpleType>
          </element>
          <element name="Item" maxOccurs="1000">
            <complexType>
              <sequence>
                <element name="Part">
                  <simpleType>
                    <restriction base="string">
                      <maxLength value="20"/>
                    </restriction>
                  </simpleType>
                </element>
                <element name="Price" type="float"/>
              </sequence>
            </complexType>
          </element>
        </sequence>
      </complexType>
      <element name="PurchaseOrder" type="po:PurchaseOrderType"/>
    </schema>';
BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd', doc);
END;
/

The registration creates the internal types. We can now create a table to store the XML values and also create a nested table to store the Items.

SQL> CREATE TABLE MYPOs OF XMLType
   2 XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
   3 ELEMENT "PurchaseOrder"
   4 VARRAY xmldata."Item" store as table item_nested;

Table created

Now, we insert a purchase order into this table.

INSERT INTO MyPos
VALUES(
 XMLType(
 '<PurchaseOrder
   xmlns="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd   
   http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd">
  <PONum>1001</PONum>
    <Company>Oracle Corp</Company>
      <Item> 
        <Part>9i Doc Set</Part>
        <Price>2550</Price>
      </Item>
      <Item>
        <Part>8i Doc Set</Part>
        <Price>350</Price>
      </Item>
  </PurchaseOrder>'));

Because the XML Schema did not specify anything about maintaining the ordering, the default is to maintain the ordering and DOM fidelity. Hence the types have SYS_XDBPD$ attribute to store the extra information needed to maintain the ordering of nodes and to capture extra items such as comments, processing instructions and so on.

The SYS_XDBPD$ attribute also maintains the existential information for the elements (that is, whether the element was present or not in the input document). This is needed for elements with scalar content, because they map to simple relational columns. In this case, both empty and missing scalar elements map to NULL values in the column and only the SYS_XDBPD$ attribute can help distinguish the two cases. The XPath rewrite mechanism takes into account the presence or absence of the SYS_XDBPD$ attribute and rewrites queries appropriately.

Now this table has a hidden XMLData column of type "PurchaseOrder_T" that stores the actual data.

Rewriting XPath Expressions: Mapping Types and Path Expressions

XPath expression mapping of types and topics are described in the following sections.


Schema-Based: Mapping for a Simple XPath

A rewrite for a simple XPath involves accessing the attribute corresponding to the XPath expression. Table 5-11 lists the XPath map:

Table 5-11 Simple XPath Mapping for purchaseOrder XML Schema

XPath Expression Maps to
/PurchaseOrder column XMLData
/PurchaseOrder/@PurchaseDate column XMLData."PurchaseDate"
/PurchaseOrder/PONum column XMLData."PONum"
/PurchaseOrder/Item elements of the collection XMLData."Item"
/PurchaseOrder/Item/Part attribute "Part" in the collection XMLData."Item"


Mapping for Scalar Nodes

An XPath expression can contain a text() operator which maps to the scalar content in the XML document. When rewriting, this maps directly to the underlying relational columns.

For example, the XPath expression "/PurchaseOrder/PONum/text()" maps to the SQL column XMLData."PONum" directly.

A NULL value in the PONum column implies that the text value is not available, either because the text node was not present in the input document or the element itself was missing. This is more efficient than accessing the scalar element, because in this case there is no need to check for the existence of the element in the SYS_XBDPD$ attribute.

For example, the XPath "/PurchaseOrder/PONum" also maps to the SQL attribute XMLData."PONum",

However, in this case, XPath rewrite also has to check for the existence of the element itself, using the SYS_XDBPD$ in the XMLData column.


Schema-Based: Mapping of Predicates

Predicates are mapped to SQL predicate expressions. As discussed earlier, since the predicates are rewritten into SQL, the comparison rules of SQL are used instead of the XPath 1.0 semantics.

Example 5-22 Mapping Predicates

For example the predicate in the XPath expression:

/PurchaseOrder[PONum=1001 and Company = "Oracle Corp"]

maps to the SQL predicate:

( XMLData."PONum" = 20 and XMLData."Company" = "Oracle Corp")

For example, the following query is rewritten to the structured (object-relational) equivalent, and will not require Functional evaluation of the XPath.

SELECT Extract(value(p),'/PurchaseOrder/Item').getClobval()
   FROM MYPOs p
   WHERE ExistsNode(value(p),'/PurchaseOrder[PONum=1001 
     AND Company = "Oracle Corp"]') =1;

Schema-Based: Mapping of Collection Predicates

XPath expressions may involve relational operators with collection expressions. In Xpath 1.0, conditions involving collections are existential checks. In other words, even if one member of the collection satisfies the condition, the expression is true.

Example 5-23 Mapping Collection Predicates

For example the collection predicate in the XPath:

/PurchaseOrder[Items/Price > 200]
-- maps to a SQL collection expression:
exists(SELECT null FROM TABLE (XMLDATA."Item") x
                   WHERE  x."Price" > 200 )

For example, the following query is rewritten to the structured equivalent.

SELECT Extract(value(p),'/PurchaseOrder/Item').getClobval()
  FROM MYPos p
  WHERE ExistsNode(value(p),'/PurchaseOrder[Item/Price > 400]') = 1;

More complicated rewrites occur when you have a collection <condition> collection. In this case, if at least one combination of nodes from these two collection arguments satisfy the condition, then the predicate is deemed to be satisfied.

Example 5-24 Mapping Collection Predicates, Using existsNode()

For example, consider a fictitious XPath which checks to see if a Purchaseorder has Items such that the price of an item is the same as some part number:

/PurchaseOrder[Items/Price = Items/Part]
-- maps to a SQL collection expression:
   exists(SELECT null 
            FROM   TABLE (XMLDATA."Item") x
            WHERE  EXISTS (SELECT null 
                             FROM  TABLE(XMLDATA."Item") y
                             WHERE  y."Part" = x."Price"))

For example, the following query is rewritten to the structured equivalent:

SELECT Extract(value(p),'/PurchaseOrder/Item').getClobval()
  FROM  MYPOs p
  WHERE ExistsNode(value(p),'/PurchaseOrder[Item/Price = Item/Part]') = 1;

Schema-Based: Document Ordering with Collection Traversals

Most of the rewrite preserves the original document ordering. However, because the SQL system does not guarantee ordering on the results of subqueries, when selecting elements from a collection using the extract() function, the resultant nodes may not be in document order.

Example 5-25 Document Ordering with Collection Traversals

For example:

SELECT extract(value(p),'/PurchaseOrder/Item[Price>2100]/Part')
  FROM MYPOs p;

is rewritten to use subqueries as shown in the following:

SELECT (SELECT XMLAgg(XMLForest(x."Part" AS "Part")) 
          FROM   TABLE (XMLData."Item") x
          WHERE  x."Price" > 2100)
  FROM MYPOs p;

Though in most cases, the result of the aggregation would be in the same order as the collection elements, this is not guaranteed and hence the results may not be in document order. This is a limitation that may be fixed in future releases.


Schema-Based: Collection Index

An XPath expression can also access a particular index of a collection For example, "/PurchaseOrder/Item[1]/Part" is rewritten to extract out the first Item of the collection and then access the Part attribute within that.

If the collection has been stored as a VARRAY value, then this operation retrieves the nodes in the same order as present in the original document. If the mapping of the collection is to a nested table, then the order is undetermined. If the VARRAY value is stored as an Ordered Collection Table (OCT), (the default for the tables created by the schema compiler, if storeVarrayAsTable="true" is set), then this collection index access is optimized to use the IOT index present on the VARRAY value.


Schema-Based: Non-Satisfiable XPath Expressions

An XPath expression can contain references to nodes that cannot be present in the input document. Such parts of the expression map to SQL NULL values during rewrite. For example the XPath expression: "/PurchaseOrder/ShipAddress" cannot be satisfied by any instance document conforming to the purchaseorder.xsd XML Schema, because the XML Schema does not allow for ShipAddress elements under PurchaseOrder. Hence this expression would map to a SQL NULL literal.


Schema-Based: Namespace Handling

Namespaces are handled in the same way as the function-based evaluation. For schema-based documents, if the function (like existsNode() or extract()) does not specify any namespace parameter, then the target namespace of the schema is used as the default namespace for the XPath expression.

Example 5-26 Handling Namespaces

For example, the XPath expression /PurchaseOrder/PONum is treated as /a:PurchaseOrder/a:PONum with xmlns:a="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd" if the SQL function does not explicitly specify the namespace prefix and mapping. In other words:

SELECT * FROM MYPOs p
  WHERE  ExistsNode(value(p), '/PurchaseOrder/PONum') = 1;

is equivalent to the query:

SELECT * 
  FROM MYPOs p
  WHERE ExistsNode(
          value(p),
          '/PurchaseOrder/PONum',
          'xmlns="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd')
        = 1;

When performing XPath rewrite, the namespace for a particular element is matched with that of the XML Schema definition. If the XML Schema contains elementFormDefault="qualified" then each node in the XPath expression must target a namespace (this can be done using a default namespace specification or by prefixing each node with a namespace prefix).

If the elementFormDefault is unqualified (which is the default), then only the node that defines the namespace should contain a prefix. For instance if the purchaseorder.xsd had the element form to be unqualified, then the existsNode() function should be rewritten as:

existsNODE(
  value(p),
  '/a:PurchaseOrder/PONum',                   
  'xmlns:a="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd")
= 1;

Note:

For the case where elementFormDefault is unqualified, omitting the namespace parameter in the SQL function existsNode() in the preceding example, would cause each node to default to the target namespace. This would not match the XML Schema definition and consequently would not return any result. This is true whether the function is rewritten or not.


Schema-Based: Date Format Conversions

The default date formats are different for XML Schema and SQL. Consequently, when rewriting XPath expressions involving comparisons with dates, you must use XML formats.

Example 5-27 Date Format Conversions

For example, the expression:

[@PurchaseDate="2002-02-01"]

cannot be simply rewritten as:

XMLData."PurchaseDate" = "2002-02-01"

because the default date format for SQL is not YYYY-MM-DD. Hence during XPath rewrite, the XML format string is added to convert text values into date datatypes correctly. Thus the preceding predicate would be rewritten as:

XMLData."PurchaseDate" = TO_DATE("2002-02-01","SYYYY-MM-DD");

Similarly when converting these columns to text values (needed for extract(), and so on), XML format strings are added to convert them to the same date format as XML.


Existential Checks for Scalar Elements and Attributes

The existsNode function checks for the existence of a the node targeted by the XPath while extract returns the targeted node. In both cases we need to do special checks for scalar elements and for attributes used in existsNode expressions. This is because the SQL column value alone cannot distinguish if a scalar element or attribute is missing or is empty. In both these cases, the SQL column value is NULL. Note that these special checks are not required for intermediate (non-scalar) elements since the SQL UDT value itself will indicate the absence or emptiness of the element.

For instance, an expression of the form,

existsNode(value(p),'/PurchaseOrder/PONum/text()') = 1;

is rewritten to become

(p.XMLDATA."PONum" IS NOT NULL)

since the user is only interested in the text value of the node. If however, the expression was,

existsNode(value(p),'/PurchaseOrder/PONum') = 1;

then we need to check the SYS_XDBPD$ attribute in the parent to check if the scalar element is empty or is missing.

(check-node-exists(p.XMLDATA."SYS_XDBPD$","PONum") IS NOT NULL)

The check-node-exists operation is implemented using internal SQL operators and returns null if the element or attribute is not present in the document. In the case of extract expressions, this check needs to be done for both attributes and elements. An expression of the form,

Extract(value(p),'/PurchaseOrder/PONum')

maps to an expression like,

CASE WHEN check-node-exists(p.XMLDATA.SYS_XDBPD$", "PONum") IS NOT NULL 
   THEN XMLElement("PONum", p.XMLDATA."PONum")
   ELSE NULL END;

Note:

Be aware of this overhead when writing your existsNode or extract expressions. You can avoid the overhead by using the text() node in the XPath, using extractValue to get only the node's value or by turning off the DOM fidelity for the parent node.

The DOM fidelity can be turned off by setting the value of the attribute maintainDOM in the element definition to be false. In this case all empty scalar elements or attributes are treated as missing.


Rewrite of SQL Functions

Section "Rewriting XPath Expressions: Mapping Types and Path Expressions" explains the various path mappings. This section talks in detail about the differences in rewrite for some of these functions. The objective of this is to explain the overhead involved in certain types of operations using existsNode or extract which can be avoided.

XPath Expression Rewrites for ExistsNode

existsNode() returns a numerical value 0 or 1 indicating if the XPath returns any nodes (text() or element nodes). Based on the mapping discussed in the earlier section, an existsNode() simply checks if a scalar element is not NULL in the case where the XPath targets a text() node or a non-scalar node and checks for the existence of the element using the SYS_XDBPD$ otherwise. If the SYS_XDBPD$ attribute is absent, then the existence of a scalar node is determined by the NULL information for the scalar column.


existsNode Mapping with Document Order Maintained

Table 5-12 shows the mapping of various XPaths in the case of existsNode() when document ordering is preserved, that is, when SYS_XDBPD$ exists and maintainDOM="true" in the schema document.

Table 5-12 XPath Mapping for existsNode() with Document Ordering Preserved

XPath Expression Maps to
/PurchaseOrder CASE WHEN XMLData IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/@PurchaseDate CASE WHEN Check_Node_Exists(XMLData.SYS_XDBPD$, 'PurchaseDate') IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/PONum CASE WHEN Check_Node_Exists(XMLData.SYS_XDBPD$, 'PONum') IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder[PONum = 2100] CASE WHEN XMLData."PONum"=2100 THEN 1 ELSE 0
/PurchaseOrder[PONum = 2100]/@PurchaseDate CASE WHEN XMLData."PONum"=2100 AND Check_Node_Exists(XMLData.SYS_XDBPD$, 'PurchaseDate') IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/PONum/text() CASE WHEN XMLData."PONum" IS NOT NULL THEN 1 ELSE 0
/PurchaseOrder/Item CASE WHEN EXISTS ( SELECT NULL FROM TABLE (XMLData."Item") x WHERE value(x) IS NOT NULL) THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part CASE WHEN EXISTS (SELECT NULL FROM TABLE (XMLData."Item") x WHERE Check_Node_Exists(x.SYS_XDBPD$, 'Part') IS NOT NULL) THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part/text() CASE WHEN EXISTS (SELECT NULL FROM TABLE (XMLData."Item") x WHERE x."Part" IS NOT NULL) THEN 1 ELSE 0 END

Example 5-28 existsNode Mapping with Document Order Maintained

Using the preceding mapping, a query which checks whether the PurchaseOrder with number 2100 contains a part with price greater than 2000:

SELECT count(*)
FROM   mypos p
WHERE EXISTSNODE(value(p),'/PurchaseOrder[PONum=1001 AND 
                                          Item/Price > 2000]')= 1;

would become:

SELECT count(*) 
FROM   mypos p
WHERE  CASE WHEN 
           p.XMLData."PONum" = 1001 AND 
           EXISTS ( SELECT NULL 
                    FROM   TABLE ( XMLData."Item") p
                    WHERE  p."Price" > 2000 )) THEN 1 ELSE 0 END  = 1;

The CASE expression gets further optimized due to the constant relational equality expressions and this query becomes:

SELECT count(*) 
FROM   mypos p
WHERE  p.XMLData."PONum" = 1001 AND 
       EXISTS ( SELECT NULL 
                FROM   TABLE ( p.XMLData."Item") x
                WHERE  x."Price" > 2000 );

which would use relational indexes for its evaluation, if present on the Part and PONum columns.


ExistsNode mapping without DOM fidelity

If the SYS_XDBPD$ does not exist (that is, if the XML Schema specifies maintainDOM="false") then NULL scalar columns map to non-existent scalar elements. Hence you do not need to check for the node existence using the SYS_XDBPD$ attribute. Table 5-13 shows the mapping of existsNode() in the absence of the SYS_XDBPD$ attribute.

Table 5-13 XPath Mapping for existsNode Without Document Ordering

XPath Expression Maps to
/PurchaseOrder CASE WHEN XMLData IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/@PurchaseDate CASE WHEN XMLData.'PurchaseDate' IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/PONum CASE WHEN XMLData."PONum" IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder[PONum = 2100] CASE WHEN XMLData."PONum" = 2100 THEN 1 ELSE 0 END
/PurchaseOrder[PONum = 2100]/@PurchaseOrderDate CASE WHEN XMLData."PONum" = 2100 AND XMLData."PurchaseDate" NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/PONum/text() CASE WHEN XMLData."PONum" IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/Item CASE WHEN EXISTS (SELECT NULL FROM TABLE (XMLData."Item") x WHERE value(x) IS NOT NULL) THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part CASE WHEN EXISTS (SELECT NULL FROM TABLE (XMLData."Item") x WHERE x."Part" IS NOT NULL) THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part/text() CASE WHEN EXISTS (SELECT NULL FROM TABLE (XMLData."Item") x WHERE x."Part" IS NOT NULL) THEN 1 ELSE 0 END

Rewrite for extractValue

extractValue() is a shortcut for extracting text nodes and attributes using extract() and then using a getStringVal() or getNumberVal() to get the scalar content. extractValue returns the text nodes for scalar elements or the values of attribute nodes. extractValue() cannot handle returning multiple values or non-scalar elements.

Table 5-14 shows the mapping of various XPath expressions in the case of extractValue(). If an XPath expression targets an element, then extractValue retrieves the text node child of the element. Thus the two XPath expressions, /PurchaseOrder/PONum and /PurchaseOrder/PONum/text() are handled identically by extractValue and both of them retrieve the scalar content of PONum.

Table 5-14 XPath Mapping for extractValue()

XPath Expression Maps to
/PurchaseOrder Not supported - extractValue can only retrieve values for scalar elements and attributes
/PurchaseOrder/@PurchaseDate XMLData."PurchaseDate"
/PurchaseOrder/PONum XMLData."PONum"
/PurchaseOrder[PONum=2100] (SELECT TO_XML(x.XMLData) FROM Dual WHERE x."PONum" = 2100)
/PurchaseOrder[PONum=2100]/@PurchaseDate (SELECT x.XMLData."PurchaseDate") FROM Dual WHERE x."PONum" = 2100)
/PurchaseOrder/PONum/text() XMLData."PONum"
/PurchaseOrder/Item Not supported - extractValue can only retrieve values for scalar elements and attributes
/PurchaseOrder/Item/Part Not supported - extractValue cannot retrieve multiple scalar values
/PurchaseOrder/Item/Part/text() Not supported - extractValue cannot retrieve multiple scalar values

Example 5-29 Rewriting extractValue

For example, a SQL query such as:

SELECT extractValue(value(p),'/PurchaseOrder/PONum') 
   FROM   mypos p
   WHERE  extractValue(value(p),'/PurchaseOrder/PONum') = 1001;

would become:

SELECT p.XMLData."PONum"
   FROM   mypos p
   WHERE  p.XMLData."PONum" = 1001;

Because it gets rewritten to simple scalar columns, indexes if any, on the PONum attribute can be used to satisfy the query.


Creating Indexes

ExtractValue can be used in index expressions. If the expression gets rewritten into scalar columns, then the index is turned into a B*Tree index instead of a function-based index.

Example 5-30 Creating Indexes with extract

For example:

create index my_po_index on mypos x 
  (extract(value(x),'/PurchaseOrder/PONum/text()').getnumberval());

would get rewritten into:

create index my_po_index on mypos x ( x.XMLData."PONum");

and thus becomes a regular B*Tree index. This is useful, because unlike a function-based index, the same index can now satisfy queries which target the column such as:

existsNode(value(x),'/PurchaseOrder[PONum=1001]') = 1;
Rewrite of XMLSequence Function

XMLSequence can be used in conjunction with extract and the TABLE clause to unnest collection values in the XML. When used with schema-based storage, they also get rewritten to go against the underlying collection storage. For example, to get the price and part numbers of all items in a relational form, we can write a query like,

SQL> SELECT extractValue(value(p),'/PurchaseOrder/PONum') as ponum,
 Extractvalue(value(i) , '/Item/Part') as part,
 Extractvalue(value(i), '/Item/Price') as price
FROM MyPOs p,
     TABLE(XMLSequence(extract(value(p),'/PurchaseOrder/Item'))) i;
     PONUM PART                                 PRICE
---------- -------------------- ----------
      1001 9i Doc Set                      2550
      1001 8i Doc Set                      350

In this example, the extract function returns a fragment containing the list of Item elements and the XMLSequence function then converts the fragment into a collection of XMLType values one for each Item element. The TABLE clause converts the elements of the collection into rows of XMLType. The returned XML from the TABLE clause is used to extract out the Part and the Price.

XPath rewrite will rewrite the extract and the XMLSequence function so that it will become a simple select from the Item_nested nested table.

SQL> EXPLAIN PLAN
FOR SELECT extractValue(value(p),'/PurchaseOrder/PONum') AS ponum,
 extractValue(value(i) , '/Item/Part') AS part,
 extractValue(value(i), '/Item/Price') AS price
FROM MyPOs p,
     TABLE(XMLSequence(extract(value(p),'/PurchaseOrder/Item'))) i;

Explained

SQL> @utlxpls.sql

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
| Id  | Operation                                    | Name              |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |              |
|   1 |  NESTED LOOPS                            |              |
|   2 |   TABLE ACCESS FULL                | ITEM_NESTED  |
|   3 |   TABLE ACCESS BY INDEX ROWID | MYPOS           |
|*  4 |    INDEX UNIQUE SCAN              | SYS_C002973  |
----------------------------------------------------------------------------

Predicate Information (identified by operation id)
--------------------------------------------------
   4 - access("NESTED_TABLE_ID"="P"."SYS_NC0001100012$")

The EXPLAIN PLAN output shows that the optimizer is able to use a simple nested loops join between the Item_nested nested table and MyPOs table. You can also query the Item values further and create appropriate indexes on the nested table to speed up such queries.

For example, if we want to search on the Price to get all the expensive items, we could create an index on the Price column on the nested table. The following EXPLAIN PLAN uses the Price index to get the list of items and then joins back with the MYPOs table to get the PONum value.

SQL> CREATE INDEX price_index ON item_nested ("Price");

Index created.

SQL> EXPLAIN PLAN FOR
     SELECT extractValue(value(p),'/PurchaseOrder/PONum') AS ponum,
            extractValue(value(i) , '/Item/Part') AS part,
            extractValue(value(i), '/Item/Price') AS price
     FROM  MyPOs p,
          TABLE(XMLSequence(extract(value(p),'/PurchaseOrder/Item'))) i
     WHERE extractValue(value(i),'/Item/Price') > 2000;

Explained.

SQL> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
| Id  | Operation                                    | Name               | 
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |               |
|   1 |  NESTED LOOPS                            |               |
|   2 |   TABLE ACCESS BY INDEX ROWID | ITEM_NESTED   |
|*  3 |    INDEX RANGE SCAN                | PRICE_INDEX   |
|   4 |   TABLE ACCESS BY INDEX ROWID | MYPOS         |
|*  5 |    INDEX UNIQUE SCAN              | SYS_C002973   |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("ITEM_NESTED"."Price">2000)
   5 - access("NESTED_TABLE_ID"="P"."SYS_NC0001100012$")
Rewrite for extract()

The extract() function retrieves the results of XPath as XML. The rewrite for extract() is similar to that of extractValue() for those Xpath expressions involving text nodes.


Extract Mapping with DOM fidelity

Table 5-15 shows the mapping of various XPath in the case of extract() when document order is preserved (that is, when SYS_XDBPD$ exists and maintainDOM="true" in the schema document).

Table 5-15 XPath Mapping for extract() with Document Ordering Preserved

XPath Maps to
/PurchaseOrder XMLForest(XMLData as "PurchaseOrder")
/PurchaseOrder/@PurchaseDate CASE WHEN Check_Node_Exists(XMLData.SYS_XDBPD$, 'PurchaseDate') IS NOT NULL THEN XMLElement("", XMLData."PurchaseDate") ELSE NULL END;
/PurchaseOrder/PONum CASE WHEN Check_Node_Exists(XMLData.SYS_XDBPD$, 'PONum') IS NOT NULL THEN XMLElement("PONum", XMLData."PONum") ELSE NULL END
/PurchaseOrder[PONum=2100] (SELECT XMLForest(XMLData as "PurchaseOrder") from dual WHERE XMLData."PONum" = 2100)
/PurchaseOrder[PONum = 2100]/@PurchaseDate (SELECT CASE WHEN Check_Node_Exists(XMLData.SYS_XDBPD$, 'PurchaseDate') IS NOT NULL THEN XMLElement("", XMLData."PurchaseDate") ELSE NULL END FROM Dual WHERE XMLData."PONum" = 2100)
/PurchaseOrder/PONum/text() XMLElement("", XMLData."PONum")
/PurchaseOrder/Item (SELECT XMLAgg(XMLForest(value(p) as "Item")) FROM TABLE (XMLData."Item") p)
/PurchaseOrder/Item/Part (SELECT XMLAgg(CASE WHEN CHECK_Node_Exists(p.SYS_XDBPD$, 'Part') IS NOT NULL THEN XMLForest(p."Part" As "Part") ELSE NULL END) FROM TABLE(XMLData."Item") p)
/PurchaseOrder/Item/Part/text() (SELECT XMLAgg(XMLElement("", p."Part")) FROM TABLE(XMLData."Item") p)

Example 5-31 XPath Mapping for extract() with Document Ordering Preserved

Using the mapping in Table 5-15, a query that extracts the PONum element where the purchaseorder contains a part with price greater than 2000:

SELECT extract(value(p),'/PurchaseOrder[Item/Part > 2000]/PONum')
FROM   PurchaseOrder_table p;

would become:

SELECT (SELECT CASE WHEN check_node_exists(p.XMLData.SYS_XDBPD$, 'PONum') 
                         IS NOT NULL
                THEN XMLElement("PONum", p.XMLData."PONum") 
                ELSE NULL END)
        FROM  DUAL
        WHERE  EXISTS( SELECT NULL 
                       FROM   TABLE ( XMLData."Item") p
                       WHERE  p."Part" > 2000)
       )
FROM PurchaseOrder_table p;

Extract mapping without DOM fidelity

If the SYS_XDBPD$ does not exist, that is, if the XML Schema specifies maintainDOM="false", then NULL scalar columns map to non-existent scalar elements. Hence you do not need to check for the node existence using the SYS_XDBPD$ attribute. Table 5-16 shows the mapping of existsNode() in the absence of the SYS_XDBPD$ attribute.

Table 5-16 XPath Mapping for extract() Without Document Ordering Preserved

XPath Equivalent to
/PurchaseOrder XMLForest(XMLData AS "PurchaseOrder")
/PurchaseOrder/@PurchaseDate XMLForest(XMLData."PurchaseDate" AS "PurchaseDate")
/PurchaseOrder/PONum XMLForest(XMLData."PONum" AS "PONum")
/PurchaseOrder[PONum = 2100] (SELECT XMLForest(XMLData AS "PurchaseOrder") FROM Dual WHERE XMLData."PONum" = 2100)
/PurchaseOrder[PONum = 2100]/@PurchaseDate (SELECT XMLForest(XMLData."PurchaseDate" AS "PurchaseDate "") FROM DUAL WHERE XMLData."PONum" = 2100)
/PurchaseOrder/PONum/text() XMLForest(XMLData.PONum AS "")
/PurchaseOrder/Item (SELECT XMLAgg(XMLForest(value(p) as "Item") FROM TABLE (XMLData."Item") p)
/PurchaseOrder/Item/Part (SELECT XMLAgg(XMLForest(p."Part" AS "Part") FROM TABLE (XMLData."Item") p)
/PurchaseOrder/Item/Part/text() (SELECT XMLAgg(XMLForest(p. "Part" AS "Part")) FROM TABLE (XMLData."Item") p)

Optimizing updates using updateXML()

A regular update using updateXML() involves updating a value of the XML document and then replacing the whole document with the newly updated document.

When XMLType is stored object relationally, using XML Schema mapping, updates are optimized to directly update pieces of the document. For example, updating the PONum element value can be rewritten to directly update the XMLData.PONum column instead of materializing the whole document in memory and then performing the update.

updateXML() must satisfy the following conditions for it to use the optimization:

  • The XMLType column supplied to updateXML() must be the same column being updated in the SET clause. For example:

    UPDATE PurchaseOrder_table p SET value(p) = updatexml(value(p),...);
  • The XMLType column must have been stored object relationally using Oracle XML DB XML Schema mapping.

  • The XPath expressions must not involve any predicates or collection traversals.

  • There must be no duplicate scalar expressions.

  • All XPath arguments in the updateXML() function must target only scalar content, that is, text nodes or attributes. For example:

    UPDATE PurchaseOrder_table p SET value(p) =
        updatexml(value(p),'/PurchaseOrder/@PurchaseDate','2002-01-02',
                           '/PurchaseOrder/PONum/text()', 2200);

If all the preceding conditions are satisfied, then the updateXML is rewritten into a simple relational update. For example:

UPDATE PurchaseOrder_table p SET value(p) =
updatexml(value(p),'/PurchaseOrder/@PurchaseDate','2002-01-02',
                       '/PurchaseOrder/PONum/text()', 2200);

becomes:

UPDATE PurchaseOrder_table p
  SET p.XMLData."PurchaseDate" = TO_DATE('2002-01-02','SYYYY-MM-DD'),
      p.XMLData."PONum" = 2100;

DATE Conversions

Date datatypes such as DATE, gMONTH, and gDATE have different format in XML Schemas and SQL. In such cases, if the updateXML() has a string value for these columns, then the rewrite automatically puts the XML format string to convert the string value correctly. Thus string value specified for DATE columns, must match the XML date format and not the SQL DATE format.

Diagnosing XPath Rewrite

To determine if your XPath expressions are getting rewritten, you can use one of the following techniques:

Using Explain Plans

This section shows how you can use the explain plan to examine the query plans after rewrite. See Chapter 3, " Using Oracle XML DB", "Understanding and Optimizing XPath Rewrite" for examples on how to use EXPLAIN PLAN to optimize XPath rewrite.

With the explained plan, if the plan does not pick applicable indexes and shows the presence of the SQL function (such as existsNode or extract), then you know that the rewrite has not occurred. You can then use the events described later to understand why the rewrite did not happen.

For example, using the MYPOs table, we can see the use of explain plans. We create an index on the Company element of PurchaseOrder to show how the plans differ.

SQL> CREATE INDEX company_index ON MyPOs e
       (extractValue(object_value,'/PurchaseOrder/Company'));

Index created.

SQL> EXPLAIN PLAN FOR 
       SELECT  extractValue(value(p),'/PurchaseOrder/PONum')
         FROM MyPOs p
         WHERE existsNode(value(p),'/PurchaseOrder[Company="Oracle"]')=1;

Explained.

SQL> @utlxpls.sql

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
| Id  | Operation                                  | Name                 | Rows | Bytes | Cost |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                          |              |        |              |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYPOS              |            |        |              |
|*  2 |   INDEX RANGE SCAN                | COMPANY_INDEX |           |        |              |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("MYPOS"."SYS_NC00010$"='Oracle')

In this explained plan, you can see that the predicate uses internal columns and picks up the index on the Company element. This shows clearly that the query has been rewritten to the underlying relational columns.

In the following query, we are trying to perform an arithmetic operation on the Company element which is a string type. This is not rewritten and hence the explain plan shows that the predicate contains the original existsNode expression. Also, since the predicate is not rewritten, a full table scan instead of an index range scan is used.

SQL> EXPLAIN PLAN FOR
       SELECT  extractValue(value(p),'/PurchaseOrder/PONum')
         FROM MyPOs p
         WHERE existsNode(value(p),
                 '/PurchaseOrder[Company+PONum="Oracle"]') = 1;

Explained.

SQL> @utlxpls.sql

PLAN_TABLE_OUTPUT
-----------------------------------------------------------
| Id  | Operation                 | Name  
-----------------------------------------------------------
|   0 | SELECT STATEMENT   |
|*  1 |  FILTER                    |
|   2 |   TABLE ACCESS FULL| MYPOS
|*  3 |   TABLE ACCESS FULL| ITEM_NESTED
-----------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(EXISTSNODE(SYS_MAKEXML('C6DB2B4A1A3B0
                      6CDE034080020E5CF39',2300,"MYPOS"."XMLEXTRA",
              "MYPOS"."XMLDATA"),
      '/PurchaseOrder[Company+PONum="Oracle"]')=1)
   3 - filter("NESTED_TABLE_ID"=:B1)

Using Events

Events can be set in the initialization file or can be set for each session using the ALTER SESSION statement. The XML events can be used to turn off functional evaluation, turn off the query rewrite mechanism and to print diagnostic traces.

Turning off Functional Evaluation (Event 19021)

By turning on this event, you can raise an error whenever any of the XML functions are not rewritten and get evaluated. The error ORA-19022 - XML XPath functions are disabled will be raised when such functions execute. This event can also be used to selectively turn off functional evaluation of functions. Table 5-17 lists the various levels and the corresponding behavior.

Table 5-17 Event Levels and Behaviors

Event Behavior
Level 0x1 Turn off functional evaluation of all XML functions.
Level 0x2 Turn off functional evaluation of extract.
Level 0x4 Turn off functional evaluation of existsNode.
Level 0x8 Turn off functional evaluation of transform.
Level 0x10 Turn off functional evaluation of extractValue.
Level 0x20 Turn off the functional evaluation of UpdateXML.
Level 0x200 Turn off functional evaluation of XMLSequence

For example,

ALTER SESSION SET EVENTS '19021 trace name context forever, level 1';

would turn off the functional evaluation of all the XML operators listed earlier. Hence when you perform the query shown earlier that does not get rewritten, you will get an error during the execution of the query.

SQL> SELECT value(p) FROM MyPOs p
     WHERE Existsnode(value(p),
                 '/PurchaseOrder[Company+PONum="Oracle"]')=1 ;

ERROR:
ORA-19022: XML XPath functions are disabled
Tracing reasons for non-rewrite

Event 19027 with level 8192 (0x2000) can be used to dump traces that indicate the reason that a particular XML function is not rewritten. For example, to check why the query described earlier, did not rewrite, we can set the event and run an explain plan:

SQL> alter session set events '19027 trace name context forever, level 8192';Session altered.SQL> EXPLAIN PLAN FOR
     SELECT value(p) from MyPOs p
     WHERE Existsnode(value(p),'/PurchaseOrder[Company+100="Oracle"]')=1;Explained.

This writes the following the Oracle trace file explaining that the rewrite for the XPath did not occur since there were non-numeric inputs to an arithmetic function.

NO REWRITE        XPath ==> /PurchaseOrder[Company+PONum = "Oracle" ]        Reason ==> non numeric inputs to arith{2}{4}