Make XML elements required based on attribute values in XSD

风格不统一 提交于 2019-11-27 07:25:16

问题


My requirement is to have an XSD file which checks the elements based on attribute values. I was able to write XSD up to a point where I can restrict the attribute values of Application/@Type. Can anyone help me to complete the XSD file where I can make some elements required based on the Application/@Type attribute?

I want to make

  • PackageArg required only when Application/@Type is "Batch"
  • Version required only when Application/@Type is "Service"
  • Project required only when Application/@Type is Web" or "Service"

XML File

<Applications>        
    <Application Name="ConfigManagement" Type="Web">            
        <ProjectDirName>ConfigManagement</ProjectDirName>
        <Project>Web.ConfigManagement.csproj</Project>
        <OutputDirName>ConfigManagement</OutputDirName>            
    </Application>
    <Application Name="Util" Type="Web">            
        <ProjectDirName>Web</ProjectDirName>
        <Project>Web.csproj</Project>        
        <OutputDirName>Util</OutputDirName>    
    </Application>
    <Application Name="ConfigService" Type="Service">
        <ProjectDirName>WebServices\ConfigService</ProjectDirName>
        <Project>ConfigService.csproj</Project>    
        <Version>2015\04</Version>
        <OutputDirName>ConfigService</OutputDirName>
    </Application>
    <Application Name="DeliverEmail" Type="Batch">        
        <ProjectDirName>\Batch\DeliverEmail</ProjectDirName>
        <PackageArg>Release</PackageArg>        
        <OutputDirName>Tidal\DeliverEmail</OutputDirName>            
    </Application>
</Applications>

XSD File

<xs:element name="Applications" maxOccurs="1">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Application" maxOccurs="unbounded" minOccurs="1">
        <xs:complexType>
          <xs:all>
            <xs:element type="xs:string" name="ProjectDirName"/>
            <xs:element type="xs:string" name="Project" minOccurs="0"/>
            <xs:element type="xs:string" name="Version" minOccurs="0"/>
            <xs:element type="xs:string" name="PackageArg" minOccurs="0"/>
            <xs:element type="xs:string" name="OutputDirName"/>
          </xs:all>
          <xs:attribute type="xs:string" name="Name" use="optional"/>
          <xs:attribute name="Type" use="required">
            <xs:simpleType>
              <xs:restriction base="xs:string">
                <xs:enumeration value="Web"/>
                <xs:enumeration value="Batch"/>
                <xs:enumeration value="Service"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

回答1:


Update: OP has edited question to remove the use of xs:assert and has stated in comments that validation must take place in C#. The answer to OP's question now becomes:

You cannot enforce a constraint that varies the requiredness of an element based on an attribute value using XSD 1.0, and Microsoft does not support XSD 1.1, therefore you must either relax your constraints or check them outside of your XSD.


Original XSD 1.1 answer

(Retained for benefit of future readers)

You're close, but your assertion,

      <xs:assert test="count(./PackageArg[@type eq 'Batch']) eq 1"/>

tests for @type on PackageArg when it should test for @Type on Application.

The following XSD will validate your XML and enforce your attribute-dependent requirements:

XSD 1.1

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
           vc:minVersion="1.1">
  <xs:element name="Applications">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Application" maxOccurs="unbounded" minOccurs="1">
          <xs:complexType>
            <xs:all>
              <xs:element type="xs:string" name="ProjectDirName"/>
              <xs:element type="xs:string" name="Project" minOccurs="0"/>
              <xs:element type="xs:string" name="Version" minOccurs="0"/>
              <xs:element type="xs:string" name="PackageArg" minOccurs="0"/>
              <xs:element type="xs:string" name="OutputDirName"/>
            </xs:all>
            <xs:attribute type="xs:string" name="Name" use="optional"/>
            <xs:attribute name="Type" use="required">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:enumeration value="Web"/>
                  <xs:enumeration value="Batch"/>
                  <xs:enumeration value="Service"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:attribute>
            <xs:assert test="PackageArg or @Type != 'Batch'"/>
            <xs:assert test="Version or @Type != 'Service'"/>
            <xs:assert test="Project or not(@Type = 'Web' or @Type = 'Service')"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Be aware that Microsoft does not support XSD 1.1. (You've tagged your question with 'msxml').



来源:https://stackoverflow.com/questions/30606320/make-xml-elements-required-based-on-attribute-values-in-xsd

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!