XML Schema 1.1 断言:如何捕获动态类型错误?

XML Schema 1.1 assertions: How to catch a dynamic type error?

我目前正在努力处理 XML 模式 1.1 中的断言。 XML Schema 1.1 建议 states 如果断言在执行期间发生错误,则断言被违反。这种行为看似合理,但在试图理解评估结果时可能会造成一些混乱。让我解释一下:

下面的例子XSD解释定义了两个元素:str和dec。元素 str 的值必须为 "A" 或 "B"。元素 dec 必须是一个数字。此外,如果 str 的值为 "A",则 dec 必须为正。我试图通过使用断言来定义最后一个 属性:

<?xml version="1.0" encoding="utf-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="data">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="str">
          <xs:simpleType>
            <xs:restriction base="xs:string">
              <xs:enumeration value="A"/>
              <xs:enumeration value="B"/>
            </xs:restriction>
          </xs:simpleType>
        </xs:element>
        <xs:element name="dec" type="xs:decimal"/>
      </xs:sequence>
      <xs:assert test="str != 'A' or dec gt 0"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

以下 XML 文件无效,因为元素 str 的值为 "X",这是不允许的。

<?xml version="1.0" encoding="utf-8" ?>
<data>
  <str>X</str>
  <dec>5</dec>
</data>

当我现在使用 Saxon 9.6.0.6 验证 XML 文件时,我得到以下输出:

Validation error on line 3 column 16 of test.xml:
  XSD: The content "X" of element <str> does not match the required simple type. Value "X"
  contravenes the enumeration facet "A, B" of the type of element str
  Validating /data[1]/str[1]
  See http://www.w3.org/TR/xmlschema11-2/#cvc-datatype-valid clause 1
Warning: on line 1 
  Internal error: value doesn't match its type annotation. Value "X" contravenes the
  enumeration facet "A, B" of the type of element str
Validation error at data on line 5 column 8 of test.xml:
  XSD: Element data does not satisfy assertion str != 'A' or dec gt 0
  Validating /data[1]

如您所见,我收到了针对一个问题(元素 str 的非法值)报告的两个错误。我发现这种行为非常令人困惑,因为它更难看出真正的问题(错误的值,而不是失败的断言)。

有什么方法可以"catch"断言中的类型错误,使断言在这个例子中不会失败吗?

有意思。与大多数验证器一样,Saxon 会尝试通过在单个 运行 中捕获尽可能多的验证错误来提供帮助。但这仅在错误彼此独立时才有用。在已知无效的值上测试断言不是很有帮助:但是当然,断言是由不知道已经报告了哪些错误的 XPath 处理器执行的"blindly"。

Saxon 在这里报告 "internal error" 的事实表明它不应该以这种方式工作。我会记录一个错误,看看我们能做些什么。

断言相当奇怪,因为它们对半验证的数据进行操作:这使得关于它们是对类型化值还是非类型化值进行操作的规则相当复杂。在这种情况下,我怀疑以更具防御性的方式编写您的断言可能会有所帮助。但是将 'dec must be positive if str has the value "A"' 更直接地编码为 "if (str='A') then dec>0 else true()".

可能更有意义