【问题标题】:Restricting number of occurrences of an element based on its attribute value in XSD possible?可以根据 XSD 中的属性值限制元素的出现次数吗?
【发布时间】:2018-09-14 01:52:26
【问题描述】:

我正在研究基于 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 元素具有相同的值。其他属性可以(并且非常有意义)是相同的。

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

【问题讨论】:

  • 您的问题标题谈到根据属性值限制元素的出现次数。您在解释中没有提到任何属性值,所以我根本不清楚您要强加的规则是什么。一般来说,这种规则需要 XSD 1.1,但最好在明确说明之前知道规则到底是什么。
  • @MichaelKay 将添加它。这是uri 的值,但是现在我看到该示例的每个属性都相同,因此确实令人困惑。我确实提到了 URI 是示例之前的限制规则。
  • 我认为您只是说Services 中的每个Service 都必须具有不同的@uri 值,这就是xs:unique 的用途。

标签: xml xsd schema


【解决方案1】:

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

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

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

【讨论】:

  • 我不明白最后一部分“不是任意数量的”。我正在寻找关于 uri 的唯一性,因此拥有多个具有相同 uriService 元素不是我想要的。
  • @rbaleksandar 这正是我的回答正在做的;提到的是您在标题中发布的问题,您在其中要求一般“限制”(即上限/下限),而不是唯一性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
  • 2014-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多