如何在XSD中定义机构用户可以免费验证的复杂规则?

问题描述

我们维护一个开放源代码项目,该项目在机构(主要是图书馆,档案馆,博物馆)中使用。作为程序的一部分,用户必须在XML文件中描述其域模型。最初,它仅以示例形式记录,与此同时,我们编写了一个XSD文件,其中描述了所有允许的元素。如果XML中提到了此问题,并且使用了功能强大的编辑器(例如Eclipse可以做到),则会显示错误,类似于拼写更正。

现在有一些更复杂的值和属性组合没有意义,我们想对此进行验证。当然,加载文件时,我们可以在Java程序中执行此操作,但是如果有一个编辑器也将其显示错误,那就更好了。我为此查看了Schematron,但是Eclipse似乎不支持功能插件没有使其超过Beta状态,并且我在Eclipse Market中找不到关于Schematron的任何信息),而我发现支持的编辑器Schematron,必须为企业用户购买。我们没有预算。期。我安装了BaseX,它显然具有Schematron插件,但是在编辑时它根本不检查DTD,只是为了确保格式正确。也没有用于针对DTD运行验证的按钮,或者我没有找到它,或者我不知道如何开始验证。

但是我也愿意接受另一种解决方案,它不必是Schematron,主要是它最终可以工作。也许我可以描述我想用XSD本身实现什么,而我只是不知道该怎么做。

这是我要验证的“复杂星座”的意思的示例。域模型定义键(数据存储为键值对)。

<ruleset xmlns="http://names.kitodo.org/ruleset/v2"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://names.kitodo.org/ruleset/v2 ruleset.xsd">
    <declaration>
        <division id="item"><label>Item</label></division>

        <key id="myString">             <!-- Correct: A 'key' without      -->
            <label>String</label>       <!-- 'option' elements defines a   -->
        </key>                          <!-- string type.                  -->

        <key id="myEnum">               <!-- Correct: A 'key' with         -->
            <label>Enumeration</label>  <!-- 'option' elements defines an  -->
            <option value="value1"/>    <!-- enum. 'option' must be        -->
            <option value="value2"/>    <!-- repeatable.                   -->
            <option value="value3"/>
        </key>

        <key id="boolean">              <!-- Correct: A 'key' of codomain  -->
            <label>Boolean</label>      <!-- type 'boolean' must have      -->
            <codomain type="boolean"/>  <!-- exactly one option value (for -->
            <option value="on"/>        <!-- true. Absence = false).       -->
        </key>

        <key id="unsavableBoolean">     <!-- Error: A boolean 'key' with   -->
            <label>Boolean</label>      <!-- no value can't be saved since -->
            <codomain type="boolean"/>  <!-- there is no value to write.   -->
        </key>                          <!-- (Empty value is forbidden.)   -->

        <key id="deadCodeBoolean">      <!-- Dead code: Multiple values    -->
            <label>Boolean</label>      <!-- don't make sense. They can be -->
            <codomain type="boolean"/>  <!-- considered dead code and are  -->
            <option value="value1"/>    <!-- typically showing something   -->
            <option value="value2"/>    <!-- is wrong here. (Maybe wrong   -->
            <option value="value3"/>    <!-- codomain?)                    -->
        </key>
    </declaration>
</ruleset>

我希望编辑器将其中的最后两个标记为不正确。这是当前的完整XSD文件

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:ruleset="http://names.kitodo.org/ruleset/v2"
           elementFormDefault="qualified"
           targetNamespace="http://names.kitodo.org/ruleset/v2">

    <xs:complexType name="AcquisitionStage">
        <xs:sequence>
            <xs:element name="setting" minOccurs="1" maxOccurs="unbounded" type="ruleset:Setting"/>
        </xs:sequence>
        <xs:attribute use="required" type="xs:string" name="name"/>
    </xs:complexType>

    <xs:complexType name="CodomainElement">
        <xs:attribute type="ruleset:Type" name="type"/>
        <xs:attribute type="xs:anyURI" name="namespace"/>
    </xs:complexType>

    <xs:complexType name="DeclarationElement">
        <xs:sequence>
            <xs:element name="division" minOccurs="1" maxOccurs="unbounded" type="ruleset:Division" />
            <xs:element name="key" minOccurs="0" maxOccurs="unbounded" type="ruleset:Key"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Division">
        <xs:sequence>
            <xs:element type="ruleset:Label" minOccurs="1" maxOccurs="unbounded" name="label"/>
            <xs:element type="ruleset:SubdivisionByDateElement" minOccurs="0" maxOccurs="1" name="subdivisionByDate"/>
        </xs:sequence>
        <xs:attribute use="required" type="xs:NMTOKEN" name="id"/>
        <xs:attribute type="xs:string" name="processtitle"/>
        <xs:attribute type="xs:boolean" name="withWorkflow"/>
        <xs:attribute type="xs:NMTOKEN" name="dates"/>
        <xs:attribute type="xs:string" name="scheme"/>
        <xs:attribute type="ruleset:DivisionUseAttribute" name="use"/>
    </xs:complexType>

    <xs:simpleType name="DomainAttribute">
        <xs:restriction base="xs:string">
            <xs:enumeration value="description"/>
            <xs:enumeration value="digitalProvenance"/>
            <xs:enumeration value="rights"/>
            <xs:enumeration value="source"/>
            <xs:enumeration value="technical"/>
            <xs:enumeration value="mets:div"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="EditingElement">
        <xs:sequence>
            <xs:element name="setting" minOccurs="0" maxOccurs="unbounded" type="ruleset:Setting"/>
            <xs:element name="acquisitionStage" minOccurs="0" maxOccurs="unbounded" type="ruleset:AcquisitionStage"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Key">
        <xs:sequence>
            <xs:element name="label" minOccurs="1" maxOccurs="unbounded" type="ruleset:Label"/>
            <xs:element name="codomain" minOccurs="0" maxOccurs="1" type="ruleset:CodomainElement"/>
            <xs:element name="option" minOccurs="0" maxOccurs="unbounded" type="ruleset:Option"/>
            <xs:element name="pattern" minOccurs="0" maxOccurs="1" type="xs:string"/>
            <xs:element name="preset" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
            <xs:element name="key" minOccurs="0" maxOccurs="unbounded" type="ruleset:Key"/>
        </xs:sequence>
        <xs:attribute use="required" type="xs:NMTOKEN" name="id"/>
        <xs:attribute type="ruleset:DomainAttribute" name="domain" default="description"/>
        <xs:attribute type="ruleset:KeyUseAttribute" name="use"/>
    </xs:complexType>

    <xs:complexType name="Label">
        <xs:simpleContent>
            <xs:extension base="xs:string">
                <xs:attribute type="xs:string" name="lang"/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>

    <xs:element name="namespace">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="option" minOccurs="0" maxOccurs="unbounded" type="ruleset:Option"/>
            </xs:sequence>
            <xs:attribute type="xs:anyURI" name="about"/>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="Option">
        <xs:sequence>
            <xs:element name="label" minOccurs="0" maxOccurs="unbounded" type="ruleset:Label"/>
        </xs:sequence>
        <xs:attribute use="required" type="xs:string" name="value"/>
    </xs:complexType>

    <xs:complexType name="Rule">
        <xs:sequence>
            <xs:element name="permit" minOccurs="0" maxOccurs="unbounded" type="ruleset:Rule"/>
        </xs:sequence>
        <xs:attribute type="xs:NMTOKEN" name="division"/>
        <xs:attribute type="xs:NMTOKEN" name="key"/>
        <xs:attribute type="xs:string" name="value"/>
        <xs:attribute type="xs:nonNegativeInteger" name="minOccurs"/>
        <xs:attribute type="xs:nonNegativeInteger" name="maxOccurs"/>
        <xs:attribute type="ruleset:Unspecified" name="unspecified"/>
    </xs:complexType>

    <xs:element name="ruleset">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="declaration" minOccurs="1" maxOccurs="1" type="ruleset:DeclarationElement"/>
                <xs:element name="correlation" minOccurs="0" maxOccurs="1">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="restriction" minOccurs="1" maxOccurs="unbounded" type="ruleset:Rule"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="editing" minOccurs="0" maxOccurs="1" type="ruleset:EditingElement"/>
            </xs:sequence>
            <xs:attribute type="xs:string" name="lang"/>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="Setting">
        <xs:sequence>
            <xs:element name="setting" minOccurs="0" maxOccurs="unbounded" type="ruleset:Setting"/>
        </xs:sequence>
        <xs:attribute type="xs:NMTOKEN" name="key"/>
        <xs:attribute type="xs:boolean" name="alwaysShowing" default="false"/>
        <xs:attribute type="xs:boolean" name="editable" default="true"/>
        <xs:attribute type="xs:boolean" name="excluded" default="false"/>
        <xs:attribute type="xs:boolean" name="multiline" default="false"/>
    </xs:complexType>

    <xs:complexType name="SubdivisionByDateElement">
        <xs:sequence>
            <xs:element name="division" minOccurs="1" maxOccurs="unbounded" type="ruleset:Division"/>
        </xs:sequence>
        <xs:attribute name="yearBegin">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:pattern value="--((0[1-9]|1[0-2])-([01][1-9]|10|2[0-8]))|((0[13-9]|1[0-2])-(29|30))|((0[13578]|1[0-2])-31)"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
    </xs:complexType>

    <xs:simpleType name="Type">
        <xs:restriction base="xs:string">
            <xs:enumeration value="anyURI"/>
            <xs:enumeration value="boolean"/>
            <xs:enumeration value="date"/>
            <xs:enumeration value="integer"/>
            <xs:enumeration value="string"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="Unspecified">
        <xs:restriction base="xs:string">
            <xs:enumeration value="unrestricted"/>
            <xs:enumeration value="forbidden"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="KeyUseAttribute">
        <xs:restriction>
            <xs:simpleType>
                <xs:list>
                    <xs:simpleType>
                        <xs:restriction base="xs:token">
                            <xs:enumeration value="authorLastName"/>
                            <xs:enumeration value="dataSource"/>
                            <xs:enumeration value="displaySummary"/>
                            <xs:enumeration value="higherlevelIdentifier"/>
                            <xs:enumeration value="processtitle"/>
                            <xs:enumeration value="recordIdentifier"/>
                            <xs:enumeration value="title"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:list>
            </xs:simpleType>
            <xs:minLength value="1"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="DivisionUseAttribute">
        <xs:restriction>
            <xs:simpleType>
                <xs:list>
                    <xs:simpleType>
                        <xs:restriction base="xs:token">
                            <xs:enumeration value="createChildrenFromParent"/>
                            <xs:enumeration value="createChildrenWithCalendar"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:list>
            </xs:simpleType>
            <xs:minLength value="1"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

我想要的是(伪代码):

<xs:complexType name="Key">
    <xs:sequence>
        <xs:element name="label" minOccurs="1" maxOccurs="unbounded" type="ruleset:Label"/>
        <xs:element name="codomain" minOccurs="0" maxOccurs="1" type="ruleset:CodomainElement"/>

        <IF test="codomain == 'boolean'">
            <xs:element name="option" minOccurs="1" maxOccurs="1" type="ruleset:Option"/>
        <ELSE />
            <xs:element name="option" minOccurs="0" maxOccurs="unbounded" type="ruleset:Option"/>
        </IF>

        <xs:element name="pattern" minOccurs="0" maxOccurs="1" type="xs:string"/>
        <xs:element name="preset" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
        <xs:element name="key" minOccurs="0" maxOccurs="unbounded" type="ruleset:Key"/>
    </xs:sequence>
    <xs:attribute use="required" type="xs:NMTOKEN" name="id"/>
    <xs:attribute type="ruleset:DomainAttribute" name="domain" default="description"/>
    <xs:attribute type="ruleset:KeyUseAttribute" name="use"/>
</xs:complexType>

我试图编写一些Schematron规则,但是我不知道它是否正确,因为我还没有找到测试该规则的方法

<xs:complexType name="Key">
   <xs:annotation>
       <xs:appinfo>
           <sch:pattern name="codomain type boolean requires exactly one option">
               <sch:rule context="//ruleset:key[ruleset:codomain/@type='boolean']">
                   <sch:report test="number(/ruleset:option) = 0">
                       Boolean key "<sch:value-of select="/@id"/>" requires an &lt;option value="..."/&gt; element.
                   </sch:report>
                   <sch:report test="number(/ruleset:option) &gt; 1">
                       Boolean key "<sch:value-of select="/@id"/>" cannot have more than one &lt;option/&gt; element.
                   </sch:report>
               </sch:rule>
           </sch:pattern>
       </xs:appinfo>
   </xs:annotation>
   <xs:sequence>
       <xs:element name="label" minOccurs="1" maxOccurs="unbounded" type="ruleset:Label"/>
       <xs:element name="codomain" minOccurs="0" maxOccurs="1" type="ruleset:CodomainElement"/>
       <xs:element name="option" minOccurs="0" maxOccurs="unbounded" type="ruleset:Option"/>
       <xs:element name="pattern" minOccurs="0" maxOccurs="1" type="xs:string"/>
       <xs:element name="preset" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
       <xs:element name="key" minOccurs="0" maxOccurs="unbounded" type="ruleset:Key"/>
   </xs:sequence>
   <xs:attribute use="required" type="xs:NMTOKEN" name="id"/>
   <xs:attribute type="ruleset:DomainAttribute" name="domain" default="description"/>
   <xs:attribute type="ruleset:KeyUseAttribute" name="use"/>
</xs:complexType>

任何有关如何进行此处操作的建议将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...