如何解决如何在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 <option value="..."/> element.
</sch:report>
<sch:report test="number(/ruleset:option) > 1">
Boolean key "<sch:value-of select="/@id"/>" cannot have more than one <option/> 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 举报,一经查实,本站将立刻删除。