HOWTO: Validate XML data

Sometimes the “how to validate XML” question arises again on the OTN XMLDB Forum. A quick start would be to read up on the XMLDB FAQ Forum questions were Mark Drake demonstrates XML validation via some good examples. Another resource would be to read the Oracle XMLDB Developers Guide chapter about “Transforming and Validating XMLType Data“.

People who just like me, try to answer for fun and/or as a mind game the questions on a Oracle OTN forum, and knowing that if you do not ask for specifics, that you will have to deal with “the merry go round exercise”: With every answer given, you discover that this wasn’t the solution which was hoped for. Sometimes I am up for this because I don’t want to be bitching about:

  • What database version are you using?
  • Give a test case that contains:
    • an XML document
    • an XML Schema
    • the used statements (SQL/XMLQuery/etc)
    • the wanted end result
  • etc…

Sometimes it is just fun, to see if you are able to predict what the solution will be in the end (although it isn’t effective – I know).

The following examples are based on such an XMLDB OTN question: “Loading a hierarchichal XML it into relational tables”. The first step asked for was how to validate XML…

Until now I have given 4 examples, which I thought are good food for a blog post, based on XMLIsValid or are “embedded” in how the XMLType table has been created.

  1. XML data contained in XMLType
  2. XML data contained in an XMLType Table(or Column), constrained by an XML Schema
  3. XML data stored in the XDB Repository (WebDAV)
  4. XML data stored on Disk (Outside the database)

And yeah there are even more combinations I can think off – like storing (not registering) an XML schema in the repository.

The basis for the examples are the ones given by Mark (see here for the XML Schema)

SQL>  SELECT * FROM v$version;
 
BANNER
------------------------------------------------------------------------------
Oracle DATABASE 11g Enterprise Edition Release 11.1.0.7.0 - Production
PL/SQL Release 11.1.0.7.0 - Production
CORE    11.1.0.7.0      Production
TNS FOR Linux: Version 11.1.0.7.0 - Production
NLSRTL Version 11.1.0.7.0 - Production
 
5 ROWS selected.

XMLType Instance Document

XML data is given by an XMLType.

SQL> SELECT schema_url FROM user_xml_schemas;
 
SCHEMA_URL
--------------------------------------------------
test
 
1 ROW selected.
 
SQL> WITH stuff AS
  2     (SELECT xmltype('<root>
  3                        <mandatory>Hello World</mandatory>
  4                        <enumeration>A</enumeration>
  5                        <minlength>ABCD</minlength>
  6                        <maxlength>WXYZ</maxlength>
  7                        <maxoccurs>1</maxoccurs>
  8                        <maxoccurs>2</maxoccurs>
  9                        <minoccurs>1</minoccurs>
 10                        <minoccurs>2</minoccurs>
 11                        <optional>Goodbye</optional>
 12                      </root>')
 13      xmlcol
 14      FROM dual
 15     )
 16  SELECT XMLisValid(xmlcol,'test') AS "VALID?"
 17  FROM   stuff
 18  ;
 
   VALID?
---------
        1
 
1 ROW selected.
 
SQL> WITH stuff AS
  2     (SELECT xmltype('<root>
  3                        <mandatory>Hello World</mandatory>
  4                        <enumeration>A</enumeration>
  5                        <minlength>ABCD</minlength>
  6                        <maxlength>WXYZ</maxlength>
  7                        <maxoccurs>1</maxoccurs>
  8                        <maxoccurs>2</maxoccurs>
  9                        <minoccurs>1</minoccurs>
 10                        <minoccurs>2</minoccurs>
 11                        <optional>Goodbye</optional>
 12                      </root>')
 13      xmlcol
 14      FROM dual
 15     )
 16  SELECT decode(XMLisValid(xmlcol,'test'), 1, 'TRUE', 0, 'FALSE') 
 17  AS "VALID?"
 18  FROM   stuff;
 
VALID?
------
TRUE
 
1 ROW selected.
 
SQL> WITH stuff AS
  2     (SELECT xmltype('<root>
  3                        <mandatory>Hello World</mandatory>
  4                        <illegal>Hello World</illegal>
  5                        <enumeration>A</enumeration>
  6                        <minlength>ABCD</minlength>
  7                        <maxlength>WXYZ</maxlength>
  8                        <maxoccurs>1</maxoccurs>
  9                        <maxoccurs>2</maxoccurs>
 10                        <minoccurs>1</minoccurs>
 11                        <minoccurs>2</minoccurs>
 12                        <optional>Goodbye</optional>
 13                      </root>')
 14      xmlcol
 15      FROM dual
 16     )
 17  SELECT decode(XMLisValid(xmlcol,'test'), 1, 'TRUE', 0, 'FALSE') 
 18  AS "VALID?"
 19  FROM   stuff;
 
VALID?
------
FALSE
 
1 ROW selected.
 
SQL>

XMLType Table / Column Data

XML data is stored in an XMLType table. This could have been an Binary XML table which also can be constrained by an XML Schema (or XML Schemata).

SQL> INSERT INTO ROOT_TABLE VALUES (xmltype(
  2  '<root>
  3     <mandatory>Hello World</mandatory>
  4     <enumeration>A</enumeration>
  5     <minlength>ABCD</minlength>
  6     <maxlength>WXYZ</maxlength>
  7     <maxoccurs>1</maxoccurs>
  8     <maxoccurs>2</maxoccurs>
  9     <minoccurs>1</minoccurs>
 10     <minoccurs>2</minoccurs>
 11     <optional>Goodbye</optional>
 12  </root>'
 13  ))
 14  / 
 
1 ROW created.
 
SQL> INSERT INTO ROOT_TABLE VALUES (xmltype(
  2  '<root>
  3     <mandatory>Hello World</mandatory>
  4     <illegal>Hello World</illegal>
  5     <enumeration>A</enumeration>
  6     <minlength>ABCD</minlength>
  7     <maxlength>WXYZ</maxlength>
  8     <maxoccurs>1</maxoccurs>
  9     <maxoccurs>2</maxoccurs>
 10     <minoccurs>1</minoccurs>
 11     <minoccurs>2</minoccurs>
 12     <optional>Goodbye</optional>
 13  </root>'
 14  ))
 15  / 
INSERT INTO ROOT_TABLE VALUES (xmltype(
                               *
ERROR at line 1:
ORA-30937: No schema definition FOR 'Illegal' (namespace '##local') IN parent '/Root'
 
SQL> SELECT schema_url FROM user_xml_schemas;
 
SCHEMA_URL
--------------------------------------------------
test
 
1 ROW selected.
 
SQL> SET long 10000000
SQL> SELECT * FROM root_table;
 
SYS_NC_ROWINFO$
--------------------------------------------------
<root>
  <mandatory>Hello World</mandatory>
  <enumeration>A</enumeration>
  <minlength>ABCD</minlength>
  <maxlength>WXYZ</maxlength>
  <maxoccurs>1</maxoccurs>
  <maxoccurs>2</maxoccurs>
  <minoccurs>1</minoccurs>
  <minoccurs>2</minoccurs>
  <optional>Goodbye</optional>
</root>
 
1 ROW selected.
 
SQL> SELECT XMLisValid(VALUE(rt),'test') AS "VALID?"
  2  FROM root_table rt
  3  ;
 
   VALID?
---------
        1
 
1 ROW selected.
 
SQL> -- This example is the same as given by Mark in the XMLDB Forum FAQ 
SQL>

XMLType data stored in the XDB Repository / WebDAV

XML data is stored as a file resource in the WebDAV XDB Foldering.

 
SQL> -- CREATE A XML FILE CALLED "Hierarchichal_XML.xml" as a FILE(aka Resource) in the XDB WebDAV foldering in the root dir "/"
 
SQL> DECLARE
  2   
  3     XMLdoc XMLType:=xmltype('<root>
  4               <mandatory>Hello World</mandatory>
  5               <illegal>Hello World</illegal>
  6               <enumeration>A</enumeration>
  7               <minlength>ABCD</minlength>
  8               <maxlength>WXYZ</maxlength>
  9               <maxoccurs>1</maxoccurs>
 10               <maxoccurs>2</maxoccurs>
 11               <minoccurs>1</minoccurs>
 12               <minoccurs>2</minoccurs>
 13               <optional>Goodbye</optional>
 14            </root>');
 15  
 16  BEGIN
 17   
 18       IF (DBMS_XDB.CREATERESOURCE('/Hierarchichal_XML.xml', XMLdoc))
 19       THEN NULL;
 20       ELSE
 21          DBMS_OUTPUT.PUT_LINE('Resource Hierarchichal_XML.xml could NOT be created');
 22       END IF;
 23       commit;
 24   
 25  END;
 26  / 
 
PL/SQL PROCEDURE successfully completed.
 
SQL> SELECT xdbURIType ('/Hierarchichal_XML.xml').getClob() FROM dual;
 
XDBURITYPE('/HIERARCHICHAL_XML.XML').GETCLOB()
--------------------------------------------------------------------------------
<root>
  <mandatory>Hello World</mandatory>
  <illegal>Hello World</illegal>
  <enumeration>A</enumeration>
  <minlength>ABCD</minlength>
  <maxlength>WXYZ</maxlength>
  <maxoccurs>1</maxoccurs>
  <maxoccurs>2</maxoccurs>
  <minoccurs>1</minoccurs>
  <minoccurs>2</minoccurs>
  <optional>Goodbye</optional>
</root>
 
1 ROW selected.
 
SQL> SELECT SCHEMA_URL, QUAL_SCHEMA_URL
  2  FROM user_xml_schemas
  3  WHERE schema_url='test';
 
SCHEMA_URL
---------------------------
QUAL_SCHEMA_URL
---------------------------
test
http://xmlns.oracle.com/xdb/schemas/OTN/test
 
 
1 ROW selected.
 
SQL> SELECT decode(XMLisValid(xdbURIType ('/Hierarchichal_XML.xml').getXML(),'test')
  2               , 1, 'TRUE'
  3               , 0, 'FALSE') 
  4         AS "VALID?"
  5  FROM   dual
  6  ;
 
VALID
-----
FALSE
 
1 ROW selected.

XMLType data Stored on Disk (outside the Database)

XML data is stored in on disk outside the database.

SQL> CREATE directory OTNDIR AS '/tmp';
 
Directory created.
 
SQL> -- CREATE XML FILE on DISK (/tmp/Hierarchichal_XML.xml')
 
SQL> DECLARE
  2    doc  DBMS_XMLDOM.DOMDocument;
  3    xdata XMLType:=xmltype('<root>
  4                                <mandatory>Hello World</mandatory>
  5                                <illegal>Hello World</illegal>
  6                                <enumeration>A</enumeration>
  7                                <minlength>ABCD</minlength>
  8                                <maxlength>WXYZ</maxlength>
  9                                <maxoccurs>1</maxoccurs>
 10                                <maxoccurs>2</maxoccurs>
 11                                <minoccurs>1</minoccurs>
 12                                <minoccurs>2</minoccurs>
 13                                <optional>Goodbye</optional>
 14                           </root>');
 15  BEGIN
 16  
 17    doc := DBMS_XMLDOM.NewDOMDocument(xdata);
 18    DBMS_XMLDOM.WRITETOFILE(doc, 'OTNDIR/Hierarchichal_XML.xml');
 19  
 20  END;
 21  /           
 
PL/SQL PROCEDURE successfully completed.
 
SQL> -- SELECT FROM THE XML FILE on DISK (/tmp/Hierarchichal_XML.xml')
 
SQL> SELECT EXTRACT((XMLTYPE(bfilename('OTNDIR','Hierarchichal_XML.xml'),NLS_CHARSET_ID('AL32UTF8'))),'*') AS "XDATA"
  2  FROM dual;
 
XDATA
--------------------------------------------------------------------------------
<root><mandatory>Hello World</mandatory><illegal>Hello World</illegal><enumerati on>A<minlength>ABCD</minlength><maxlength>WXYZ</maxlength><maxoccu rs>1<maxoccurs>2</maxoccurs><minoccurs>1</minoccurs><minoccurs>2<optional>Goodbye</optional></minoccurs></maxoccu></enumerati></root>
 
 
1 ROW selected.
 
SQL> SELECT decode(XMLisValid(XMLTYPE(bfilename('OTNDIR','Hierarchichal_XML.xml'),NLS_CHARSET_ID('AL32UTF8')),'test')
  2               , 1, 'TRUE'
  3               , 0, 'FALSE')
  4         AS "VALID?"
  5  FROM   dual
  6  ;
 
VALID?
------
FALSE
 
1 ROW selected.

HTH

😉

Marco Gralike Written by:

One Comment

  1. September 7

    == UPDATE ==

    As this post is of long long ago, I have learned that probably the best way is NOT to use XMLisValid but when manually checking if your content is valid against the schema is to use schemaValidate()

    DECLARE
      cursor getDocuments
      IS
      SELECT rownum, xmltype(somestuff) AS OBJECT_VALUE
      FROM   TableWithXML;
    BEGIN
      FOR d IN getDocuments() loop
        BEGIN
          d.OBJECT_VALUE.schemaValidate();
        EXCEPTION WHEN OTHERS
        	THEN
        	dbms_output.put_line (d.rownum||' = INVALID => '||sqlerrm);
        END;
      END loop;
    END;
    /

    or if there is no reference or an invalid reference or you need to specify a specific reference to an XML Schema add the createSchemaBasedXML function.

    DECLARE
      cursor getDocuments
      IS
      SELECT rownum, twx.xml_columnname.createSchemaBasedXML('my_XML_Schema.xsd') 
        AS OBJECT_VALUE
      FROM   TableWithXML twx
    BEGIN
      FOR d IN getDocuments() loop
        BEGIN
          d.OBJECT_VALUE.schemaValidate();
        EXCEPTION WHEN OTHERS
          THEN
          dbms_output.put_line (d.rownum||' = INVALID => '||sqlerrm);
        END;
      END loop;
    END;
    /

Comments are closed.