Oracle® XML DB Developer's Guide 10g Release 1 (10.1) Part Number B10790-01 |
|
|
View PDF |
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:
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 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 "de Finibus Bonorum et Malorum", written by Cicero in 45 BC "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?" 1914 translation by H. Rackham "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?" Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC "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." 1914 translation by H. Rackham "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." </Notes> </po:PurchaseOrder>
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.
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:
Registering any W3C-compliant XML Schemas.
Validating your XML documents against a registered XML Schema definitions.
Registering local and global XML Schemas.
Generating XML Schema from object types.
Referencing an XML Schema owned by another user.
Explicitly referencing a global XML Schema when a local XML Schema exists with the same name.
Generating a structured database mapping from your XML Schemas during XML Schema registration. This includes generating SQL object types, collection types, and default tables, and capturing the mapping information using XML Schema attributes.
Specifying a particular SQL type mapping when there are multiple legal mappings.
Creating XMLType
tables, views and columns based on registered XML Schemas.
Performing manipulation (DML) and queries on XML Schema-based XMLType
tables.
Automatically inserting data into default tables when schema-based XML instances are inserted into Oracle XML DB repository using FTP, HTTP/WebDAV protocols and other languages.
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.
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.
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.
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.
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.
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
.
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:
registerSchema(). This registers an XML Schema with Oracle Database, given:
deleteSchema(). This deletes a previously registered XML Schema.
copyEvolve(). This function is described in Chapter 7, " XML Schema Evolution".
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; /
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.
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.
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
.
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.
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.
|
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"
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
.
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.
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.
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.
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.
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; /
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". |
XML Schemas can be registered as local or global:
Local XML Schema: An XML Schema registered as a local schema is, by default, visible only to the owner.
Global XML Schema: An XML Schema registered as a global schema is, by default, visible and usable by all database users.
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:
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 defineXMLType tables, columns, or views, validate documents, and so on. However, Oracle Database supports fully qualified XML Schema URLs, which can be specified as:
This extended URL can be used by privileged users to specify XML Schema belonging to other users. |
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.
|
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.
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.
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.
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 attributeSYS_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. |
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];
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:
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.
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 onXMLType values stored object-relationally. Note that the thin JDBC driver currently supports only XMLType values stored as CLOB values. |
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 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:
When GENTYPES
or GENTABLES
is set TRUE
, schema annotation makes it possible for developers to ensure that the names of the tables, objects, and attributes created by registerSchema()
are well-known names, compliant with any application-naming standards.
When GENTYPES
or GENTABLES
is set FALSE
, schema annotation makes it possible for developers to map between the XML Schema and existing objects and tables within the database.
To prevent the generation of mixed-case names that require the use of quoted identifies when working directly with SQL.
The most commonly used annotations are the following:
defaultTable
– Used to control the name of the default table generated for each global element when the GENTABLES
parameter is FALSE
. Setting this to ""
will prevent a default table from being generated for the element in question.
SQLName
– Used to specify the name of the SQL attribute that corresponds to each element or attribute defined in the XML Schema
SQLType
– For complexType
definitions, SQLType
is used to specify the name of the SQL object type that are corresponds to the complexType
definitions. For simpleType
definitions, SQLType
is used to override the default mapping between XML Schema data types and SQL data types. A very common use of SQLType
is to define when unbounded strings should be stored as CLOB
values, rather than VARCHAR(4000) CHAR
values (the default).
SQLCollType
– Used to specify the name of the VARRAY
type that will manage a collection of elements.
maintainDOM
– Used to determine whether or not DOM fidelity should be maintained for a given complexType
definition
storeVarrayAsTable
– Specified in the root element of the XML Schema. Used to force all collections to be stored as nested tables. There will be one nested table created for each element that specifies maxOccurs > 1
. The nested tables will be created with system-generated names.
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 |
---|---|---|---|
|
Any SQL identifier | Element name | Specifies the name of the attribute within the SQL object that maps to this XML element. |
|
Any SQL type name | Name generated from element name | Specifies the name of the SQL type corresponding to this XML element declaration. |
|
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 . |
|
Any SQL username | User registering XML Schema | Name of database user owning the type specified by SQLType . |
|
Any SQL username | User registering XML Schema | Name of database user owning the type specified by SQLCollType . |
|
true | false | true | If true, the collection is mapped to a VARRAY . If false, the collection is mapped to a NESTED TABLE . |
|
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. |
|
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. |
|
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. |
|
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. |
|
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 |
---|---|---|---|
|
Any SQL type name | Name generated from element name | Specifies the name of the SQL type corresponding to this XML element declaration. |
|
Any SQL username | User registering XML Schema | Name of database user owning the type specified by SQLType . |
|
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 |
---|---|---|---|
|
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) . |
|
true | false | false | If true, the VARRAY is stored as a table (OCT). If false, the VARRAY is stored in a LOB. |
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.
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
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.
Use DBMS_XMLSCHEMA
to set the mapping of type information for attributes and elements.
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.
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
.
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
.
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 mappingsimpleType values and complexType values 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:
An XML primitive type is mapped to the closest SQL datatype. For example, DECIMAL
, POSITIVEINTEGER
, and FLOAT
are all mapped to SQL NUMBER
.
An XML enumeration type is mapped to an object type with a single RAW(n) attribute. The value of n is determined by the number of possible values in the enumeration declaration.
An XML list or a union datatype is mapped to a string (VARCHAR2
or CLOB
) datatype in SQL.
Figure 5-3 Mapping simpleType: XML Strings to SQL VARCHAR2 or CLOBs
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 |
-- |
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.
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
.
Using XML Schema, a complexType
is mapped to a SQL object type as follows:
XML attributes declared within the complexType
are mapped to object attributes. The simpleType
defining the XML attribute determines the SQL datatype of the corresponding attribute.
XML elements declared within the complexType
are also mapped to object attributes. The datatype of the object attribute is determined by the simpleType
or complexType
defining the XML element.
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.
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>
When using XMLType
functions such as extract()
and existsNode()
remotely for XML Schema-based views or tables, you must specify the namespace completely.
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.
This section describes XPath rewrite support in Oracle XML DB and how to use it for XML Schema based structured storage.
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 |
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.
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 CLOB
s 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:
|
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:
|
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:
|
Predicates in the XPath are rewritten into SQL predicates. Predicates are not rewritten for updateXML() |
List index:
|
Indexes are rewritten to access the nth item in a collection. These are not rewritten for updateXML() . |
Wildcard traversals:
|
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:
|
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
|
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
|
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
|
XMLSequence combined with Extract, when used in a TABLE clause is rewritten to use the underlying nested table structures. |
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 /*
.
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.
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.
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
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.
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
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.
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.
XPath expression mapping of types and topics are described in the following sections.
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" |
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.
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;
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;
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.
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.
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.
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 whereelementFormDefault 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. |
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.
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 yourexistsNode 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. |
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.
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.
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.
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 |
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.
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;
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$")
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.
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;
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) |
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 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.
To determine if your XPath expressions are getting rewritten, you can use one of the following techniques:
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)
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.
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
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}