Oracle - проверить формат даты (гггг-мм-дд Thh24: mi: ssZ) в XML против XSD - PullRequest
2 голосов
/ 21 октября 2019

Версия Oracle:

Результат этого запроса 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

Введение в мою ситуацию:

Я создаю большой тип xml с помощью своей процедуры и вставляю его в свою таблицу. Я пытаюсь проверить этот файл xmltype по .xsd, который я зарегистрировал в своей базе данных. Мне удалось сократить данные xmltype и файл .xsd, чтобы я мог точно показать, в какой строке внутри файла .xml возникли проблемы.

Подготовленный мною код вы можетескопируйте и вставьте для тестирования:

Это моя простая таблица:

create table XML_DATE_TEST(
    xml_file xmltype
);

И процедура, которая создает данные xmltype и вставляет их в эту таблицу, такова:

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;

Затем я регистрирую свою схему .xsd следующим образом:

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;

И затем я вызываю свою процедуру:

BEGIN
    P_XML_DATE_TEST(2);
END;

После всего, что я пытаюсь проверить созданноеДанные xmltype из моей таблицы в отношении файла .xsd, который я зарегистрировал. Я пытаюсь сделать это двумя способами:

1.При использовании isSchemaValid

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

2.При использовании 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;

Проблема:

С первым методом, который я использую (isSchemaValid), результат, который я получаю, равен 1. Это означает, что мои данные xmltype верны по отношению к предоставленной xxd .xsd. Со вторым методом, который я использую (schemaValidate), я получаю в результате ошибку:

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.

Что я пробовал:

Когда я удаляю 'Z«Часть из формата даты все в порядке, но это не решение, которое мне подходит. Формат даты должен быть таким, как сейчас.

Ответы [ 2 ]

2 голосов
/ 21 октября 2019

Согласно XML-схеме W3C: типы данных документации часовых поясов и суффикс zulu-time Z должны поддерживаться dateTime, но в Oracle ограничение xs:dateTime выглядит какисключения, когда значение содержит часовой пояс [ db <> fiddle ]. Из документации Oracle не сразу видно, что это предполагаемое поведение, и полное ограничение dateTime не поддерживается.

Вы можете изменить схему, чтобы использовать регулярное выражение вместо xs:dateTime. Это не идеальное решение, поскольку вам нужно либо очень сложное регулярное выражение, либо вы соглашаетесь с тем, что вам может потребоваться дополнительная проверка дат, чтобы убедиться, что никто не вводит недопустимую дату (например, 2019-02-29T...), которая в противном случае прошла бы сопоставление с шаблоном. .

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;
/

дБ <> скрипка

1 голос
/ 21 октября 2019

Что-то, что хорошо с помощью isSchemaValid, не хорошо с помощью schemaValidate

Я думаю, что проблема здесь в том, что функции проверки XML могут быть очень дорогими в вычислительном отношении, поэтому Oracle - как и другие реализации - смотрит наизбегайте работы там, где это возможно.

В документации XMLDB указано , что isSchemaValid() проверяет, что ...

входной экземпляр соответствует указанной схеме. Он не изменяет статус проверки экземпляра XML.

... но schemaValidate() ...

проверяет экземпляр XML на соответствие его схеме ... [в случае успеха] статус документа изменяется на проверенный.

Это всего лишь предположение, но моя интерпретация isSchemaValid() просто проверяет, что элемент XML правильно сформирован, тогда как schemaValidate() проверяет правильностьправильная форма и содержание элементов тоже. То есть, я думаю, isSchemaValid() легче, чем isSchemaValid().

Вот почему лучший совет - не доверять XML, пока он не будет передан schemaValidate().

Конечно, более насущная проблема заключается в том, почему Oracle datetime не делаетучитывайте обозначения часовых поясов, когда стандарты XSD говорят, что это должно. Еще одно предположение, но я предполагаю, что это связано с тем, что Oracle отображает xs:datetime в свой тип данных DATE, который не поддерживает часовые пояса.

...