2

甲骨文版本:

这个查询的结果select * from v$version;是:

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

我的情况介绍:

我正在使用我的过程创建一个大型 xmltype,并将其插入到我的表中。然后,我尝试针对已在数据库中注册的 .xsd 验证创建的 xmltype 文件。我已经成功地缩短了 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;

毕竟,我去尝试根据我注册的 .xsd 文件验证表中创建的 xmltype 数据。我尝试通过两种方式做到这一点:

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。这意味着当我根据提供的 .xsd 模式验证它时,我的 xmltype 数据是正确的。使用我使用的第二种方法(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”部分时,一切正常,但这不是一个适合我的解决方案。日期的格式必须和现在一样。

4

3 回答 3

2

根据W3C XML Schema : Datatypes文档时区和 zulu-timeZ后缀,应该支持,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;
/

db<>小提琴

于 2019-10-21T10:21:42.937 回答
1

您可以通过以下方式稍微更改您的 XSD:1)在注册模式之前添加 Oracle 自己的命名空间,2)使用“SQLType”属性为 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>';

任何时区值都将被验证为 OK:db_fiddle

同样的技巧适用于属性。代替

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

更好地使用

    <xs:attribute name="SomeTimeStamp" xdb:SQLType="TIMESTAMP WITH TIME ZONE">
        <xs:simpleType>
          <xs:restriction base="xs:dateTime"/>
        </xs:simpleType>
    </xs:attribute>
于 2020-04-14T23:56:48.223 回答
1

通过 isSchemaValid 正常的事情通过 schemaValidate 不正常

我认为这里的问题是 XML 验证函数在计算上可能非常昂贵,因此 Oracle - 像其他实现一样 - 看起来尽可能避免工作。

XMLDB文档指出检查isSchemaValid()...

输入实例符合指定的模式。它不会更改 XML 实例的验证状态。

……但是schemaValidate()……

根据其模式验证 XML 实例... [如果成功] 文档的状态更改为已验证。

这只是一个猜测,但我的解释isSchemaValid()只是检查 XML 元素的格式是否正确,同时schemaValidate()验证格式是否正确以及元素的内容。也就是说,我认为isSchemaValid()比 轻isSchemaValid()

这就是为什么最好的建议是在XML 通过之前不信任它schemaValidate()

当然,更紧迫的问题是为什么 Oracledatetime在 XSD 标准要求时不允许时区表示法。这里有另一个猜测,但我认为这是因为 Oracle 映射xs:datetime到它的 DATE 数据类型,它不支持时区。

于 2019-10-21T15:45:38.813 回答