Generate XML Schema from oracle tables

Here is a nice thread describing how to generate XML schema from Oracle tables. I tried the following function and it worked great.

* Compile the following PL/SQL function:

CREATE OR REPLACE FUNCTION GEN_XML_SCHEMA(target_table varchar2) RETURN xmltype
AS
  xmlSchema XMLTYPE;
  currUser VARCHAR2(128);
BEGIN
  SELECT sys_context('USERENV','CURRENT_USER') 
  INTO currUser
  FROM dual;
 
  SELECT
    -- Begin schema
    xmlElement(
      "xsd:schema",
      xmlAttributes(
        'http://www.w3.org/2001/XMLSchema' AS "xmlns:xsd",
        'http://xmlns.oracle.com/xdb' AS "xmlns:xdb",
        'http://' || target_table || '/xsd' AS "targetNamespace",
        'http://' || target_table || '/xsd' AS "xmlns:tns",
        'qualified' AS "elementFormDefault"
      ),
      -- Base type
      xmlElement(
        "xsd:complexType",
        xmlAttributes(
          currUser || '.Base_T' AS "name"
        )
      ),
      -- Element
      xmlElement(
        "xsd:element",
        xmlAttributes(
          currUser || '.' || target_table || 'S' AS "name",
          'tns:' || currUser || '.' || target_table || 'S_T' AS "type"
        )
      ),
      -- Rows type to hold multiple rows
      xmlElement(
        "xsd:complexType",
        xmlAttributes (
          currUser || '.' || target_table || 'S_T' AS "name"
        ),
        -- Multipe rows
        xmlElement (
          "xsd:sequence",
          xmlElement (
            "xsd:element",
            xmlAttributes (
              currUser || '.' || target_table AS "name",
              'tns:' || currUser || '.' || target_table || '_T' AS "type",
              'unbounded' AS "maxOccurs"
            )
          )
        )
      ),
      -- Row type to hold single row
      xmlElement (
        "xsd:complexType",
        xmlAttributes (
          currUser || '.' || target_table || '_T' AS "name"
        ),
        xmlElement(
            "xsd:complexContent",
            xmlElement(
                "xsd:extension",
                xmlAttributes (
                  'tns:' || currUser || '.Base_T' AS "base"
                ),
                -- Individual columns
                xmlElement (
                  "xsd:sequence",
                  (
                    xmlAgg(ELEMENT)
                  )
                )
            )
        )
      )
    )
  INTO xmlSchema
  FROM (
    SELECT INTERNAL_COLUMN_ID,
      CASE
        WHEN DATA_TYPE IN ('VARCHAR2', 'CHAR') THEN
          xmlElement (
            "xsd:element",
            xmlattributes (
              column_name AS "name",
              decode(NULLABLE, 'Y', 0, 1) AS "minOccurs",
              column_name AS "xdb:SQLName",
              DATA_TYPE AS "xdb:SQLTYPE"
            ),
            xmlElement (
              "xsd:simpleType",
              xmlElement (
                "xsd:restriction",
                xmlAttributes (
                  'xsd:string' AS "base"
                ),
                xmlElement (
                  "xsd:maxLength",
                  xmlAttributes (
                  DATA_LENGTH AS "value"
                  )
                )
              )
            )
          )
        WHEN DATA_TYPE = 'DATE' THEN
          xmlElement (
            "xsd:element",
            xmlattributes (
              column_name AS "name",
              --'xsd:dateTime' as "type",
              'xsd:date' AS "type",
              decode(NULLABLE, 'Y', 0, 1) AS "minOccurs",
              column_name AS "xdb:SQLName",
              DATA_TYPE AS "xdb:SQLTYPE"
            )
          )
        WHEN DATA_TYPE = 'NUMBER' THEN
          xmlElement (
            "xsd:element",
            xmlattributes (
              column_name AS "name",
              decode(DATA_SCALE, 0, 'xsd:integer', 'xsd:double') AS "type",
              decode(NULLABLE, 'Y', 0, 1) AS "minOccurs",
              column_name AS "xdb:SQLName",
              DATA_TYPE AS "xdb:SQLTYPE"
            )
          )
        ELSE
          xmlElement (
            "xsd:element",
            xmlattributes (
              column_name AS "name",
              'xsd:anySimpleType' AS "type",
              decode(NULLABLE, 'Y', 0, 1) AS "minOccurs",
              column_name AS "xdb:SQLName",
              DATA_TYPE AS "xdb:SQLTYPE"
            )
          )
      END ELEMENT
    FROM user_tab_cols c
    WHERE TABLE_NAME = target_table
    ORDER BY internal_column_id
  );
 
  RETURN xmlSchema;
END;
/

* Run the function:

-- Complete schema
SELECT gen_xml_schema('MY_TABLE').extract('/*') FROM dual;
 
-- Select element and complexType
SELECT gen_xml_schema('RF_TAG_TXN').extract('/schema/element | /schema/complexType', 
'xmlns="http://www.w3.org/2001/XMLSchema"') FROM dual;

* Generate schema from multiple tables:

CREATE OR REPLACE DIRECTORY dir_temp AS 
    'C:\TEMP';
 
DECLARE
  TYPE tableNameArray IS varray(100) OF VARCHAR2(64);
  tableNames tableNameArray;
 
  outputFileName VARCHAR2(100) := 'MY_SCHEMA.xsd';
  outputFileHandler UTL_FILE.file_type;
 
  tableXmlType xmlType;
  xmlRootElementBegin VARCHAR2(500) := 
    '<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:xdb="http://xmlns.oracle.com/xdb"
    targetNamespace="http://my.db/xsd"
    xmlns:tns="http://my.db/xsd" 
    elementFormDefault="qualified">';
  xmlRootElementEnd VARCHAR2(500) := '</xsd:schema>';
BEGIN
  -- Database tables
  tableNames := tableNameArray(
    'TABLE1',
    'TABLE2');
 
  -- Open schema file to write
  outputFileHandler := UTL_FILE.fopen('DIR_TEMP', outputFileName, 'W');
  -- Write root element begin tag
  UTL_FILE.put_line(outputFileHandler, xmlRootElementBegin);
 
  -- Loop through all tables
  FOR tblName IN 1 .. tableNames.count loop
    DBMS_OUTPUT.put_line('Processing table: ' || tableNames(tblName));
 
    -- Generate xml schema from each table
    SELECT gen_xml_schema(tableNames(tblName)).extract(
        '/schema/element|/schema/complexType',
        'xmlns="http://www.w3.org/2001/XMLSchema"') 
    INTO tableXmlType
    FROM dual;
 
    -- Write xml schema
    IF tableXmlType IS NOT NULL THEN
      UTL_FILE.put_line(outputFileHandler, tableXmlType.getStringVal());
    END IF;
  END loop;
 
  -- Write root element end tag
  UTL_FILE.put_line(outputFileHandler, xmlRootElementEnd);
  -- Close file
  UTL_FILE.fclose(outputFileHandler);
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.put_line (DBMS_UTILITY.FORMAT_ERROR_STACK);
END;
/
This entry was posted in oracle. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

This site uses Akismet to reduce spam. Learn how your comment data is processed.