0

我正在使用 Saxon9EE.jar 来验证 XML。

我的元素有一个简单类型的断言来验证年份的日期是否在 1900 年之后,这很完美。但是对于所有使用元素名称进行验证的断言都会出错。

我的 XSD:

<?xml version="1.0" encoding="ISO-8859-1"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/">
    <xs:element name="Root">
        <xs:annotation>
            <xs:appinfo>
                <XSDVersion>1</XSDVersion>
                <fieldSeparator>|</fieldSeparator>
                <recordSeparator>\n</recordSeparator>
                <allowDiscontinousOrder>true</allowDiscontinousOrder>
                <allowIgnoreCase>false</allowIgnoreCase>
                <allowLessFields>true</allowLessFields>
                <removeInvalidChar>false</removeInvalidChar>
                <enclosedChar/>
            </xs:appinfo>
        </xs:annotation>
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Record" minOccurs="1" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="LoanOpenDate" nillable="false" minOccurs="0" maxOccurs="1">
                                <xs:annotation>
                                    <xs:appinfo>
                                        <format>AAAAAAA</format>
                                        <originalName><![CDATA[LoanOpenDate]]></originalName>
                                        <parent> </parent>
                                    </xs:appinfo>
                                </xs:annotation>
                                <xs:simpleType>
                                    <xs:restriction base="CMGDateFormat">
                                        <xs:assertion test="if(string-length($value) != 0) then true() else false()" saxon:message="LoanOpenDate, should have a valid input"/>
                                        <xs:assertion test="if(string-length($value) != 0 and string-length($value) = 10 ) then (xs:integer(substring($value,7,4)) > 1900) else true()" saxon:message="LoanOpenDate, should have a valid input, Year should be after 1900"/>

                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>



                            <xs:element name="LoanClosedDate" minOccurs="0" maxOccurs="1">
                                <xs:annotation>
                                    <xs:appinfo>
                                        <format>AAAAAAA</format>
                                        <originalName><![CDATA[LoanClosedDate]]></originalName>
                                        <parent> </parent>
                                    </xs:appinfo>
                                </xs:annotation>
                                <xs:simpleType>
                                    <xs:restriction base="CMGDateFormat">
                                        <xs:assertion test="if(string-length($value) != 0 and string-length($value) = 10 ) then (xs:integer(substring($value,7,4)) > 1900) else true()" saxon:message="LoanOpenDate, should have a valid input, Year should be after 1900"/>
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>


                        </xs:sequence>
                        <xs:attribute name="recordNumber" type="xs:string" use="required"/>
                        <xs:assert test="if(xs:integer(substring(LoanClosedDate,7,4)) > 1900 and  xs:integer(substring(LoanOpenDate,7,4)) > 1900 and  string-length(LoanClosedDate) != 0) then string-length(LoanOpenDate) != 0 else true()" saxon:message="LoanOpenDate, cannot be null if a LoanClosedDate exists"/>
                        <xs:assert test="if(string-length(LoanOpenDate) != 0  and string-length(LoanClosedDate) != 0 and xs:integer(substring(LoanClosedDate,7,4)) > 1900 and  xs:integer(substring(LoanOpenDate,7,4)) > 1900 and xs:long(concat(substring(LoanClosedDate,7,4),substring(LoanClosedDate,1,2),substring(LoanClosedDate,4,2))) != xs:long(concat(substring(LoanOpenDate,7,4),substring(LoanOpenDate1,2), substring(LoanOpenDate,4,2))))
                                                then 
                                                (xs:date(concat(substring( LoanOpenDate,7 ,4 ) ,'-',substring(LoanOpenDate,1,2 ),'-', substring(LoanOpenDate,4,2))) &lt; (xs:date(concat(substring(LoanClosedDate,7,4),'-',substring(LoanClosedDate,1,2),'-',substring(LoanClosedDate,4,2))))) 
                                                else true()" saxon:message="LoanOpenDate, cannot be a date after LoanClosedDate, cannot be null if a LoanClosedDate exists, cannot be equal to LoanClosedDate"/>


                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="CMGDateFormat">
        <xs:annotation>
            <xs:documentation>This type is used for dates requested in mm/dd/yyyy format.</xs:documentation>
        </xs:annotation>
        <xs:restriction base="xs:string">
            <xs:pattern value="((((0[1-9]|1[012])[/](0[1-9]|1[0-9]|2[0-8]))|((0[13578]|1[02])[/](29|30|31))|((0[4,6,9]|11)[/](29|30)))[/](19|[2-9][0-9])\d\d)|(02[/]29[/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96))|\s*"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

这是我正在验证的 XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Record  recordNumber = "1" >

 <LoanOpenDate><![CDATA[08/06/2008]]></LoanOpenDate>

 <LoanClosedDate><![CDATA[10/10/1900]]></LoanClosedDate>
 </Record>

 </Root>

我期望撒克逊人不应该为记录级别的断言抛出错误。应该在元素级别生成一个错误。但事实并非如此

<?xml version="1.0" encoding="UTF-8"?>
    <validation-report xmlns="http://saxon.sf.net/ns/validation"
                       system-id="file:/K:/redir/My%20Documents/MyJabberFiles/gsa4970@cmutual.com/SaxonStandalone/Loantest.xml">
       <error line="7"
              column="18"
              path="/Q{}Root[1]/Q{}Record[1]/Q{}LoanClosedDate[1]"
              xsd-part="2"
              constraint="cvc-datatype-valid.1">The content "10/10/1900" of element &lt;LoanClosedDate&gt; does not match the required simple type. Value "10/10/1900" contravenes the assertion facet "if(string-length($value) != 0 ..." of the type of element LoanClosedDate. LoanOpenDate, should have a valid input, Year should be after 1900</error>
       <error line="3"
              column="30"
              path="/Q{}Root[1]/Q{}Record[1]"
              xsd-part="1"
              constraint="sec-cvc-assertion.0">Element Record does not satisfy assertion. LoanOpenDate, cannot be a date after LoanClosedDate, cannot be null if a LoanClosedDate exists, cannot be equal to LoanClosedDate</error>
       <error line="3"
              column="30"
              path="/Q{}Root[1]/Q{}Record[1]"
              xsd-part="1"
              constraint="sec-cvc-assertion.0">Element Record does not satisfy assertion. LoanOpenDate, cannot be null if a LoanClosedDate exists</error>
       <meta-data>
          <validator name="SAXON-EE" version="9.8.0.4"/>
          <results errors="3" warnings="0"/>
          <schema file="Loan1.xsd" xsd-version="1.1"/>
          <run at="2018-01-30T10:50:42.45-06:00"/>
       </meta-data>
    </validation-report>

你能告诉我是否有解决方法,或者它是否可能是撒克逊人的错误。

4

1 回答 1

0

就像编译 Java 这样的语言一样,要报告多少错误是一个艰难的决定。您不想在第一个错误之后停止报告,因为人们希望在再次尝试验证之前更正所有错误,但您不想仅仅因为违反了语言规范(或在这种情况下为模式)。

当然可以说“如果发现任何子元素无效,则不要评估父元素上的断言”。但是,如果断言因与子元素中的错误无关的原因而为假,则您的实例文档中将出现两个错误,并且只会报告其中一个错误。

理想的解决方案可能是说“如果父元素需要访问已被发现无效的子元素,则不要评估父元素上的断言”。但这真的很难实现。

在这种情况下,您的实例文档中有一条无效数据导致架构中的三个规则失败,而 Saxon 报告了这三个规则。恐怕这就是它的工作方式。

有些人喜欢在多个阶段组织验证,因此您首先检查结构规则,然后检查“业务”规则。这涉及多个模式的管道。这是可能的,但工作量很大。

您还可以尝试聪明一点,使用 XSLT 过滤验证报告,查看与单个错误关联的路径并将它们分组。我们引入 XML 验证报告的主要原因是允许这种剪裁。

于 2018-01-31T15:33:37.787 回答