可以根据XSD中的属性值限制元素的出现次数吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可以根据XSD中的属性值限制元素的出现次数吗?相关的知识,希望对你有一定的参考价值。

我正在研究基于XML的配置文件的模式。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Configuration">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Services">
          <xs:complexType>
            <xs:sequence>
              <!--
                Each service represents a specific web service. During the validation of the XML configuration
                against the schema an additional check for multiple occurrences of the same service must take place to ensure proper configuration.

                If support for more services is added increase maxOccurs accordingly. Currently supported are
                  * Service1
                  * Service2
                  * Service3
              -->
              <xs:element maxOccurs="3" name="Service">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="ConnectionStatusUsedFor">
                      <xs:complexType>
                        <xs:attribute name="Table" type="xs:string" use="required" />
                        <xs:attribute name="Column" type="xs:string" use="required" />
                        <xs:attribute name="Row" type="xs:unsignedByte" use="required" />
                      </xs:complexType>
                    </xs:element>
                    <!--
                      Used only by service of type DeviceService
                    -->
                    <xs:element minOccurs="0" maxOccurs="1" name="VersionInfo">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="Application" type="xs:string" default="Ultimate Software" />
                          <xs:element name="OS" type="xs:string" default="Debian 9" />
                          <xs:element name="Manufacturer" type="xs:string" default="Some company" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                  <xs:attribute name="port" type="xs:unsignedShort" use="required" />
                  <!--
                    The URI is added as a path to the address where the respective service is made available for the
                    clients to connect to. The format is

                    http://127.0.0.1:[port]/[uri]

                    with [port] being the value taken from the port-attribute
                  -->
                  <xs:attribute name="uri" use="required">
                    <xs:simpleType>
                      <xs:restriction base="xs:string">
                        <xs:enumeration value="Service1.soap"/>
                        <xs:enumeration value="Service2.soap"/>
                        <xs:enumeration value="Service3.soap"/>
                      </xs:restriction>
                    </xs:simpleType>
                  </xs:attribute>
                  <xs:attribute name="Timeout" type="xs:duration" use="required" />
                  <!--
                    The version of a service (see operation GetServiceVersion) defines which operations the service supports.
                    The limited range here is defined as the smallest and largest version number available among all
                    services. This also means that some services do not support a given higher version so additional
                    service-specific check must take place during the validation of the XML configuration against the
                    schema
                  -->
                  <xs:attribute name="version" use="required">
                    <xs:simpleType>
                      <xs:restriction base="xs:unsignedByte">
                        <xs:minInclusive value="0" />
                        <xs:maxInclusive value="5" />
                      </xs:restriction>
                    </xs:simpleType>
                  </xs:attribute>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>

        <!-- rest of configuration -->

      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

以下是要针对XSD进行验证的XML文档的示例:

<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
  <Services>
    <!--
    Service:
      port    The port that we listen to for incomming data from a client
      uri     The path for the client to access the respective web service

      Note that all web services are hosted on localhost, which (given a
      port and uri) always results in http://127.0.0.1:<port>/<uri> as the
      service end point for the client to connect to

      version The version of the web service. Based on it's value (an integer)
    -->
    <Service port="8081" uri="HelloWorldService1.soap" Timeout="PT30S" version="5"/>
    <Service port="8085" uri="HelloWorldService2.soap" Timeout="PT30S" version="0"/>
    <Service port="8082" uri="HelloWorldService3.soap" Timeout="PT30S" version="1">
      <VersionInfo>
        <Application>My Software</Application>
        <OS>Debian 9</OS>
        <Manufacturer>Hello World</Manufacturer>
      </VersionInfo>
    </Service>
  </Services>

  <!-- rest of configuration -->

</Configuration>

现在的问题是,我希望将Service元素保留为添加的每个服务的公共元素,同时根据URI将实例限制为单个实例。例如,以下内容不可能(使用当前的XSD):

<Service port="8082" uri="HelloWorldService3.soap" Timeout="PT30S" version="0">
<Service port="8085" uri="HelloWorldService3.soap" Timeout="PT30S" version="1">

原因是:uri属性对于两个Service元素具有相同的值。其他属性可以(并且它完全合理)是相同的。

这可能吗?我可能会在某个时候转移到每个服务类型的单独元素,因为有些将包括未在其他服务的上下文中使用的配置服务元素。

答案

您可以尝试添加一个unique约束来选择Service元素/ uri属性对,如:

 <xs:element name="Services">
      <xs:unique name="unique-serviceUri">
        <xs:selector xpath="Service"/>
        <xs:field xpath="@uri"/>
      </xs:unique>
    [...]

当然,关于你的问题,这将允许限制具有给定属性值的一个元素,而不是任意数量的元素。

以上是关于可以根据XSD中的属性值限制元素的出现次数吗?的主要内容,如果未能解决你的问题,请参考以下文章

XSD 中元素的 ref 属性有啥作用?

如何根据属性值确定XML元素的子元素

如何使用混合值(整数和字符串)限制更改XML / XSD中的complexType?

Python 统计列表里面有多少个元素

具有相同元素名称但属性值不同的XML的XSD架构[关闭]

XSD 对属性的限制