Возможно ли ограничение числа вхождений элемента на основе значения его атрибута в XSD? - PullRequest
0 голосов
/ 13 сентября 2018

Я работаю над схемой для файла конфигурации на основе 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>

Вот пример документа XML, который должен быть проверен на соответствие XSD:

<?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.Другие атрибуты могут (и это имеет смысл) быть одинаковыми.

Возможно ли это?Возможно, в какой-то момент я перейду к отдельным элементам для каждого типа сервиса, поскольку некоторые будут включать элементы сервиса конфигурации, которые не используются в контексте других.

1 Ответ

0 голосов
/ 13 сентября 2018

Вы можете попытаться добавить ограничение unique, которое выбирает пару атрибутов Service element / uri, например:

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

Конечно, что касается вашего вопроса, это позволило бы ограничиться одним элементом с заданным значением атрибута, а не произвольным числом из них.

...