2

Oracle version:

The result of this query select * from v$version; is:

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
"CORE   11.2.0.4.0  Production"
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

Introduction to my situation:

I am creating a large xmltype with my procedure and I insert it in my table. Then I am trying to validate that created xmltype file against .xsd that I have registred in my database. I have succesfuly managed to shorten the xmltype data and the .xsd file so I can show you exactly on what line inside of the .xml file I am having problems.

Code that I have prepared you can copy and paste for testing:

This is my simple table:

create table XML_DATE_TEST(
    xml_file xmltype
);

And the procedure that is creating xmltype data and inserting it in this table is this:

CREATE OR REPLACE PROCEDURE P_XML_DATE_TEST (p_testvar in number) --
IS

    xml_help_variable xmltype;

BEGIN

    SELECT XMLELEMENT
           ("DocumentROOTTag", 
               XMLATTRIBUTES(
                   'http://www.w3.org/2001/XMLSchema-instance' "xmlns:xsi"
                   , 'XSD_TEST.xsd' "xsi:noNamespaceSchemaLocation"),
           XMLELEMENT
           ("SomeDateTag", 
           (to_char( sysdate,'yyyy-mm-dd')||'T'||to_char( sysdate,'hh24:mi:ss')||'Z'))
           )
    INTO xml_help_variable
    FROM dual
    WHERE p_testvar = 2;

INSERT INTO XML_DATE_TEST VALUES (xml_help_variable);

END P_XML_DATE_TEST;

Then I register my .xsd schema like this:

BEGIN
    DECLARE
        l_schema CLOB;
    BEGIN
        l_schema := '<?xml version="1.0" encoding="UTF-8"?>
                    <!--W3C Schema generated by XMLSpy v2009 sp1 (http://www.altova.com)-->
                    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
                        <xs:element name="DocumentROOTTag">
                            <xs:complexType>
                                <xs:sequence>
                                    <xs:element ref="SomeDateTag"/>
                                </xs:sequence>
                            </xs:complexType>
                        </xs:element>
                        <xs:element name="SomeDateTag">
                            <xs:simpleType>
                                <xs:restriction base="xs:dateTime"/>
                            </xs:simpleType>
                        </xs:element>
                    </xs:schema>';
        DBMS_XMLSCHEMA.registerSchema(schemaurl       => 'XSD_TEST.xsd', 
                                         schemadoc       => l_schema,
                                         local           => TRUE,
                                         gentypes        => FALSE,
                                         gentables       => FALSE,
                                         enablehierarchy => DBMS_XMLSCHEMA.enable_hierarchy_none); 
    END;
END;

And then I call my procedure:

BEGIN
    P_XML_DATE_TEST(2);
END;

After all of that I go and try to validate the created xmltype data from my table against .xsd file that I have registred. I try to do it in two ways:

1.By using isSchemaValid

SELECT x.xml_file.isSchemaValid('XSD_TEST.xsd')
FROM XML_DATE_TEST x;

2.By using schemaValidate

BEGIN
    DECLARE 
        XML XMLTYPE;
    BEGIN
        select x.xml_file.createSchemaBasedXML('XSD_TEST.xsd')
        INTO XML 
        from XML_DATE_TEST X;

        xmltype.schemaValidate(XML);

    END;
END;

Problem:

With the first methode that I use(isSchemaValid) the result that I get is 1. That means that my xmltype data is correct when I validate it against the provided .xsd schema. With the second methode that I use(schemaValidate) the result that I get is an error:

Error report -
ORA-30992: error occurred at Xpath /DocumentROOTTag/SomeDateTag
ORA-01830: date format picture ends before converting entire input string
ORA-06512: at "SYS.XMLTYPE", line 354
ORA-06512: at line 9
30992. 00000 -  "error occurred at Xpath %s"
*Cause:    
*Action:   See the following error and take appropriate action.

What I have tried:

When I remove the 'Z' part from the date format everything is ok but this is not a solution that is ok for me. The format of the date has to be like it is now.

VBoka
  • 8,995
  • 3
  • 16
  • 24
  • 1
    [db<>fiddle](https://dbfiddle.uk/?rdbms=oracle_18&fiddle=03dde695eae1fd12faf1a870491e0152) of the OP's issue. – MT0 Oct 21 '19 at 08:59
  • Thanks @MT0 for taking the time and creating that. Much appreciated. – VBoka Oct 21 '19 at 09:13
  • 2
    Updated [dv<>fiddle](https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=6bd9951f8c8603059472c893e793acef) with multiple date formats. It appears to accept fractional seconds but not time zones. – MT0 Oct 21 '19 at 09:20
  • @MT0, thank you for the update. I did played with the different date formats to see what is the specific problem with the schemaValidate. But the thing is that the date format that I am providing here should be accepted. It is a standard UTC format: https://en.wikipedia.org/wiki/ISO_8601 and I believe that it shoudl be ok when it is validated. Also, as I have wrote in my long question :) I am not able to change the date format because we send the .xml file after we create it and this is requested format. Thank you very much for any help you provide. – VBoka Oct 21 '19 at 09:27
  • 2
    Its not what ISO8601 supports but what [XML Schema: Datatypes](https://www.w3.org/TR/xmlschema-2/#isoformats) supports (which states that the `Z` suffix and time zone suffixes should be supported) and further to that what Oracle supports ... which I'm trying to find documentation for. – MT0 Oct 21 '19 at 09:34
  • @MT0, I agree 100%. – VBoka Oct 21 '19 at 09:36

3 Answers3

2

According to the W3C XML Schema : Datatypes documentation time zones, and the zulu-time Z suffix, should be supported by the dateTime but in Oracle the xs:dateTime restriction appears to throw exceptions when the value contains a time zone [db<>fiddle]. It is not immediately obvious from the Oracle documentation that this is intended behaviour and the full dateTime restriction is not supported.

You could change the schema to use a regular expression rather than xs:dateTime. Its not an ideal solution as you either need a very complicated regular expression or accept that you may need to do some additional validation of dates to check no-one is entering an invalid date (i.e. 2019-02-29T...) that would otherwise pass the pattern matching.

DECLARE
  l_schema CLOB;
BEGIN
  l_schema := '<?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="DocumentROOTTag">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="SomeDateTag"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="SomeDateTag">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:pattern value="\d{4}-((0[1-9]|1[0-2])-(0[1-9]|[12]\d)|(0[469]|11)-30|(0[13578]|1[02])-3[01])T([0-1]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-]0\d:[0-5]\d|[+-]1[0-3]:[0-5]\d|[+-]14:00)?"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    </xs:schema>';

  DBMS_XMLSCHEMA.registerSchema(
    schemaurl       => 'XSD_TEST.xsd', 
    schemadoc       => l_schema,
    local           => TRUE,
    gentypes        => FALSE,
    gentables       => FALSE,
    enablehierarchy => DBMS_XMLSCHEMA.enable_hierarchy_none
  ); 
END;
/

db<>fiddle

MT0
  • 143,790
  • 11
  • 59
  • 117
  • thank you VERY MUCH for your proposition but that is not a solution for my situation. I want to come to the end of the problem in one direction: Something that is ok via isSchemaValid is not ok via schemaValidate. Also, I am aware of the "pattern" solution and I have tryed it before and it works but, as you have wrote, with that I should add some more validations and that is not the way I want to go... – VBoka Oct 21 '19 at 14:59
  • one question: "It is not immediately obvious from the Oracle documentation that this is intended behaviour and the full dateTime restriction is not supported." with this you want to say that Oracle does not support this date format of mine and it is something they intended ? Thanks! – VBoka Oct 22 '19 at 05:06
  • 1
    I am not saying that Oracle do or don't support the complete W3C schema (although empirical evidence might suggest that they currently don't); what I am saying its that the documentation is not clear on what the intended behaviour of the XSD `dateTime` restriction is within Oracle (or else, I haven't found the right section of documentation yet). If you want to find out whether it is a bug then contact [My Oracle Support](https://support.oracle.com/portal/) and discuss the matter with them to get an official response. – MT0 Oct 22 '19 at 07:48
  • That is a great advice. Thank you! I just wanted to check because I was not clear on what you meant with your answer. Thank you for clarify it for me and for your answers. – VBoka Oct 22 '19 at 07:54
1

Something that is ok via isSchemaValid is not ok via schemaValidate

I think the problem here is that XML validation functions can be computationally very expensive so Oracle - like other implementations - looks to avoid work where it can.

The XMLDB documentation states that isSchemaValid() checks that ...

the input instance conforms to a specified schema. It does not change the validation status of the XML instance.

...but schemaValidate() ...

validates the XML instance against its schema ... [if successful] the document's status is changed to validated.

This is just a guess, but my interpretation is isSchemaValid() simply checks that the XML element is well-formed whereas schemaValidate() validates the well-formedness and the contents of the elements too. That is, I think isSchemaValid() is lighter than isSchemaValid().

That's why the best advice is to distrust XML until it's passed schemaValidate().

Of course, the more pressing problem is why Oracle's datetime doesn't allow for timezone notation when the XSD standards say it should. Another guess here, but I assume it's because Oracle maps xs:datetime to its DATE datatype, which doesn't support timezones.

APC
  • 144,005
  • 19
  • 170
  • 281
  • Thank you for your view of the situation. It is very interesting view on things and this was one of my fears. So ok, let's say it is lighter and that I listen to Your advice "That's why the best advice is to distrust XML until it's passed schemaValidate()." and I implement the solution @MT0 advised: "You could change the schema to use a regular expression...", it still remains to answer what you have pointed out in your last paragraph and that is what I want to find out : DOES ORACLE HAVE TO ACCEPT THIS DATE FORMAT WHEN schemaValidate() IS USED and is this Oracle's bug or there is solution... – VBoka Oct 21 '19 at 18:13
1

You might slightly change your XSD by: 1) adding Oracle own namespace before registering a schema, 2) using 'SQLType' attribute to specify element's type for Oracle:

l_schema := '<?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     xmlns:xdb="http://xmlns.oracle.com/xdb">
      <xs:element name="DocumentROOTTag">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="SomeDateTag"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="SomeDateTag" xdb:SQLType="TIMESTAMP WITH TIME ZONE" >
        <xs:simpleType>
          <xs:restriction base="xs:dateTime"/>
        </xs:simpleType>
      </xs:element>
    </xs:schema>';

Any timezoned values will be validated as OK: db_fiddle

The same trick works for attributes. Instead of

    <xs:attribute name="SomeTimeStamp" type="xs:dateTime"/>

better use

    <xs:attribute name="SomeTimeStamp" xdb:SQLType="TIMESTAMP WITH TIME ZONE">
        <xs:simpleType>
          <xs:restriction base="xs:dateTime"/>
        </xs:simpleType>
    </xs:attribute>
Osten
  • 11
  • 1
  • 5