XML 使用 XSD 断言和 Saxon.Api 的日期验证(.NET 版本)
XML date validation using XSD assertion with Saxon.Api (.NET version)
验证规则:当EndDate 不是null/empty 时,EndDate 应大于StartDate。
当我期待 none 时,雇主的最后一次输入出现错误。我做错了什么吗?
XML
<Employers>
<Employer>
<StartDate>2020-01-01</StartDate>
<EndDate></EndDate>
</Employer>
<Employer>
<StartDate>2020-01-01</StartDate>
<EndDate>2021-01-01</EndDate>
</Employer>
</Employers>
XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Employers">
<xs:complexType>
<xs:sequence>
<xs:element name="Employer" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="StartDate" type="xs:date"></xs:element>
<xs:element name="EndDate" minOccurs="0">
<xs:simpleType>
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="0" />
<xs:maxLength value="0" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:date">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:assert test="if (./EndDate eq '') then true() else ./EndDate gt ./StartDate" xmlns:saxon="http://saxon.sf.net/" saxon:message="Error: errors"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
稍作更正:
因为您的 EndDate
类型是 xs:string
和 xs:date
的并集,所以类型可能是其中之一,如果比较类型不匹配,它将失败 - 产生错误。可以通过将其转换为常见类型来修复此错误 - 这里我选择 xs:string
。现在它会根据空字符串检查日期的 xs:string
版本,而不是 xs:date
本身。
因此将您的断言更改为
<xs:assert test="if (xs:string(EndDate) eq '') then true() else EndDate gt StartDate" xmlns:saxon="http://saxon.sf.net/" saxon:message="Error: errors" />
现在它应该可以正常工作了。
在定义可以是日期或空的元素时,我的偏好是使用 minLength=0、maxLength=1 的列表类型,而不是使用 xs:date 和零长度字符串的并集.我认为这更好地反映了“空”案例代表“无日期”的语义,而不是存在的东西并且具有日期以外的类型。然后,键入的值始终为 xs:date?
,这更符合 XPath 比较运算符的语义:空大小写现在是空序列,而不是字符串。如果这样把EndDate
做成列表类型,那么比较就变成了
empty(EndDate) or EndDate gt StartDate
或者如果您愿意,
not(EndDate le StartDate)
验证规则:当EndDate 不是null/empty 时,EndDate 应大于StartDate。 当我期待 none 时,雇主的最后一次输入出现错误。我做错了什么吗?
XML
<Employers>
<Employer>
<StartDate>2020-01-01</StartDate>
<EndDate></EndDate>
</Employer>
<Employer>
<StartDate>2020-01-01</StartDate>
<EndDate>2021-01-01</EndDate>
</Employer>
</Employers>
XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="Employers">
<xs:complexType>
<xs:sequence>
<xs:element name="Employer" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="StartDate" type="xs:date"></xs:element>
<xs:element name="EndDate" minOccurs="0">
<xs:simpleType>
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="0" />
<xs:maxLength value="0" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:date">
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:assert test="if (./EndDate eq '') then true() else ./EndDate gt ./StartDate" xmlns:saxon="http://saxon.sf.net/" saxon:message="Error: errors"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
稍作更正:
因为您的 EndDate
类型是 xs:string
和 xs:date
的并集,所以类型可能是其中之一,如果比较类型不匹配,它将失败 - 产生错误。可以通过将其转换为常见类型来修复此错误 - 这里我选择 xs:string
。现在它会根据空字符串检查日期的 xs:string
版本,而不是 xs:date
本身。
因此将您的断言更改为
<xs:assert test="if (xs:string(EndDate) eq '') then true() else EndDate gt StartDate" xmlns:saxon="http://saxon.sf.net/" saxon:message="Error: errors" />
现在它应该可以正常工作了。
在定义可以是日期或空的元素时,我的偏好是使用 minLength=0、maxLength=1 的列表类型,而不是使用 xs:date 和零长度字符串的并集.我认为这更好地反映了“空”案例代表“无日期”的语义,而不是存在的东西并且具有日期以外的类型。然后,键入的值始终为 xs:date?
,这更符合 XPath 比较运算符的语义:空大小写现在是空序列,而不是字符串。如果这样把EndDate
做成列表类型,那么比较就变成了
empty(EndDate) or EndDate gt StartDate
或者如果您愿意,
not(EndDate le StartDate)