Search code examples
c#xmlxsdnotepad++

Different result between notepad++ XML Validation and C# XMLDocument.validate


I'm trying to enforce a uniqueness constraint for a combination of attributes across two elements using an XSD. The constraint works correctly in Notepad++ but not in my C# application.

I've added the following unique statement to my XSD:

<xs:unique name="uniqueEMNameParentID">
    <xs:selector xpath=".//EM"/>
    <xs:field xpath="@Name"/>
    <xs:field xpath=".//Station/@ID"/>
</xs:unique>

And this is an example of my XML:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PLC Name="PLC">
    <Type>
      <TypeDef ID="1" Name="G05" Description="" />
    </Type>
    <SA ID="01">
      <Station ID="100">
        <EM ID="01" Name="IR01" IsRobot="TRUE">          
        </EM>
      </Station>
    </SA>
    <SA ID="02">
      <Station ID="100">
        <EM ID="02" Name="IR01" IsRobot="TRUE">
        </EM>
        <EM ID="03" Name="IR03" IsRobot="TRUE">      
        </EM>
      </Station>
    </SA>
  </PLC>
</Project>

When using Notepad++ the XSD gives me the correct error: "IR01 is a duplicate key for the unique identity constraint 'uniqueEMNameParentID'." However, when validating the same XML against the XSD in C# using the code below, no error is reported:

 private void ValidateXML()
 {
     XmlSchemaSet schema = new XmlSchemaSet();
     schema.Add("", @"Z:\VMshare\Maarten\WindowsFormsApplication3\WindowsFormsApplication3\XML\XSDScheme3.xsd");
     projectXML.Schemas.Add(schema);

     projectXML.Validate((object sender, System.Xml.Schema.ValidationEventArgs args) =>
     {
         MessageBox.Show(args.Message);
     });
 }

My XML Document does not contain any namespaces, my XSD does not contain a targetnamespace and both attribute and elementformdefault are set to unqualified. Does anyone have any idea what it could be?

Note that my XML has two Station elements with the attribute ID=100. These elements both have a child element EM with the attribute name = IR01. This should not be possible.

Complete XSD:

<xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Project">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="PLC">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Type">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="TypeDef">
                                            <xs:complexType>
                                                <xs:simpleContent>
                                                    <xs:extension base="xs:string">
                                                        <xs:attribute type="xs:byte" name="ID"/>
                                                        <xs:attribute type="xs:string" name="Name"/>
                                                        <xs:attribute type="xs:string" name="Description"/>
                                                    </xs:extension>
                                                </xs:simpleContent>
                                            </xs:complexType>
                                        </xs:element>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                            <xs:element name="SA" maxOccurs="unbounded" minOccurs="0">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="Station" maxOccurs="unbounded" minOccurs="0">
                                            <xs:complexType>
                                                <xs:sequence>
                                                    <xs:element name="EM" maxOccurs="unbounded" minOccurs="0">
                                                        <xs:complexType>
                                                            <xs:sequence>
                                                                <xs:element name="Robot">
                                                                    <xs:complexType>
                                                                        <xs:sequence>
                                                                            <xs:element name="Jobs">
                                                                                <xs:complexType>
                                                                                    <xs:sequence>
                                                                                        <xs:element name="Job" maxOccurs="unbounded" minOccurs="0">
                                                                                            <xs:complexType>
                                                                                                <xs:simpleContent>
                                                                                                    <xs:extension base="xs:string">
                                                                                                        <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Description" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Type" use="optional"/>
                                                                                                    </xs:extension>
                                                                                                </xs:simpleContent>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="Areas">
                                                                                <xs:complexType>
                                                                                    <xs:sequence>
                                                                                        <xs:element name="Area" maxOccurs="unbounded" minOccurs="0">
                                                                                            <xs:complexType>
                                                                                                <xs:simpleContent>
                                                                                                    <xs:extension base="xs:string">
                                                                                                        <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Description" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="TargetEM_No" use="optional"/>
                                                                                                    </xs:extension>
                                                                                                </xs:simpleContent>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="Userbits">
                                                                                <xs:complexType mixed="true">
                                                                                    <xs:sequence>
                                                                                        <xs:element name="Userbit" maxOccurs="unbounded" minOccurs="0">
                                                                                            <xs:complexType mixed="true">
                                                                                                <xs:sequence>
                                                                                                    <xs:element name="Reference" maxOccurs="unbounded" minOccurs="0">
                                                                                                        <xs:complexType>
                                                                                                            <xs:simpleContent>
                                                                                                                <xs:extension base="xs:string">
                                                                                                                    <xs:attribute type="xs:byte" name="Area" use="optional"/>
                                                                                                                    <xs:attribute type="xs:byte" name="Job" use="optional"/>
                                                                                                                </xs:extension>
                                                                                                            </xs:simpleContent>
                                                                                                        </xs:complexType>
                                                                                                    </xs:element>
                                                                                                </xs:sequence>
                                                                                                <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                                                                <xs:attribute type="xs:string" name="Description" use="required"/>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="FZones">
                                                                                <xs:complexType mixed="true">
                                                                                    <xs:sequence>
                                                                                        <xs:element name="FZone" minOccurs="0">
                                                                                            <xs:complexType>
                                                                                                <xs:simpleContent>
                                                                                                    <xs:extension base="xs:string">
                                                                                                        <xs:attribute type="xs:byte" name="ID" use="optional"/>
                                                                                                        <xs:attribute type="xs:string" name="Function" use="optional"/>
                                                                                                    </xs:extension>
                                                                                                </xs:simpleContent>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="Programs">
                                                                                <xs:complexType>
                                                                                    <xs:sequence>
                                                                                        <xs:element name="Program" maxOccurs="unbounded" minOccurs="0">
                                                                                            <xs:complexType>
                                                                                                <xs:simpleContent>
                                                                                                    <xs:extension base="xs:string">
                                                                                                        <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="JobSequence" use="required"/>
                                                                                                        <xs:attribute type="xs:byte" name="Home" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Sheet" use="required"/>
                                                                                                    </xs:extension>
                                                                                                </xs:simpleContent>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="Tools">
                                                                                <xs:complexType>
                                                                                    <xs:sequence>
                                                                                        <xs:element name="Tool" maxOccurs="unbounded" minOccurs="0">
                                                                                            <xs:complexType>
                                                                                                <xs:simpleContent>
                                                                                                    <xs:extension base="xs:string">
                                                                                                        <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Type" use="required"/>
                                                                                                        <xs:attribute type="xs:string" name="Name" use="required"/>
                                                                                                    </xs:extension>
                                                                                                </xs:simpleContent>
                                                                                            </xs:complexType>
                                                                                        </xs:element>
                                                                                    </xs:sequence>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                            <xs:element name="UserNumbers">
                                                                                <xs:complexType>
                                                                                    <xs:simpleContent>
                                                                                        <xs:extension base="xs:string">
                                                                                            <xs:attribute type="xs:string" name="NumberRequired" use="required"/>
                                                                                        </xs:extension>
                                                                                    </xs:simpleContent>
                                                                                </xs:complexType>
                                                                            </xs:element>
                                                                        </xs:sequence>
                                                                        <xs:attribute type="xs:string" name="Name" use="optional"/>
                                                                        <xs:attribute type="xs:string" name="Manufacturer" use="optional"/>
                                                                        <xs:attribute type="xs:byte" name="RobotIndex" use="optional"/>
                                                                    </xs:complexType>
                                                                </xs:element>
                                                                <xs:element name="TypePlaceholder" minOccurs="0">
                                                                    <xs:complexType>
                                                                        <xs:simpleContent>
                                                                            <xs:extension base="xs:string">
                                                                                <xs:attribute type="xs:string" name="Name"/>
                                                                            </xs:extension>
                                                                        </xs:simpleContent>
                                                                    </xs:complexType>
                                                                </xs:element>
                                                            </xs:sequence>
                                                            <xs:attribute type="xs:byte" name="ID" use="required"/>
                                                            <xs:attribute type="xs:string" name="Name" use="required"/>
                                                            <xs:attribute type="xs:string" name="IsRobot" use="required"/>
                                                        </xs:complexType>
                                                    </xs:element>
                                                </xs:sequence>
                                                <xs:attribute type="xs:short" name="ID" use="optional"/>
                                            </xs:complexType>

                                        </xs:element>
                                    </xs:sequence>
                                    <xs:attribute type="xs:byte" name="ID" use="optional"/>
                                </xs:complexType>

                            </xs:element>
                        </xs:sequence>
                        <xs:attribute type="xs:string" name="Name"/>
                    </xs:complexType>
                </xs:element>
                <xs:element name="ImportDocuments">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="HandshakeDocument" maxOccurs="unbounded" minOccurs="0">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="xs:string">
                                            <xs:attribute type="xs:string" name="Name" use="required"/>
                                            <xs:attribute type="xs:string" name="ImportDate" use="required"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
        <xs:unique name="uniqueEMNameParentID">
            <xs:selector xpath=".//EM"/>
            <xs:field xpath="@Name"/>
            <xs:field xpath=".//Station/@ID"/>
        </xs:unique>
    </xs:element>
</xs:schema>

Complete XML

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <PLC Name="PLC">
    <Type>
      <TypeDef ID="1" Name="G05" Description="" />
    </Type>
    <SA ID="01">
      <Station ID="100">
        <EM ID="01" Name="IR01" IsRobot="TRUE">
          <Robot Name="AR01" Manufacturer="FANUC" RobotIndex="1">
            <Jobs>
              <Job ID="1" Description="Handling Step 1" Type="" />
              <Job ID="2" Description="Handling Step 2" Type="" />
              <Job ID="3" Description="Handling Step 3" Type="" />
              <Job ID="4" Description="Handling Step 4" Type="" />
              <Job ID="5" Description="Handling Step 5" Type="" />
              <Job ID="6" Description="Handling Step 6" Type="" />
            </Jobs>
            <Areas>
              <Area ID="1" Description="100TP01" TargetEM_No="" />
              <Area ID="2" Description="100FR02-FX01" TargetEM_No="" />
            </Areas>
            <Userbits>
              <Userbit ID="1" Description="Userbit1: Pick_Action">
                <Reference Area="2" Job="5" />
              </Userbit>
              <Userbit ID="2" Description="Userbit2: Drop_Action">
                <Reference Area="1" Job="1" />
                <Reference Area="1" Job="2" />
                <Reference Area="1" Job="3" />
                <Reference Area="3" Job="4" />
                <Reference Area="3" Job="6" />
              </Userbit>
              <Userbit ID="30" Description="xx_Mute_Sensors">
                <Reference Area="1" Job="1" />
                <Reference Area="2" Job="1" />
                <Reference Area="2" Job="2" />
                <Reference Area="1" Job="2" />
                <Reference Area="2" Job="3" />
                <Reference Area="1" Job="3" />
                <Reference Area="3" Job="4" />
                <Reference Area="2" Job="5" />
                <Reference Area="3" Job="6" />
              </Userbit>
              <Userbit ID="31" Description="xx_Type_Transfer">
                <Reference Area="2" Job="1" />
                <Reference Area="1" Job="1" />
                <Reference Area="1" Job="2" />
                <Reference Area="1" Job="3" />
                <Reference Area="2" Job="3" />
                <Reference Area="3" Job="4" />
                <Reference Area="2" Job="5" />
                <Reference Area="3" Job="6" />
              </Userbit>
            </Userbits>
            <FZones />
            <Programs>
              <Program ID="1" JobSequence="1;2;3;4;5;6;" Home="1" Sheet="FA01++100+IR01_P1" />
              <Program ID="2" JobSequence="2;3;4;5;6;" Home="1" Sheet="FA01++100+IR01_P1" />
              <Program ID="3" JobSequence="3;4;5;6;" Home="1" Sheet="FA01++100+IR01_P1" />
              <Program ID="4" JobSequence="4;5;6;" Home="1" Sheet="FA01++100+IR01_P1" />
              <Program ID="5" JobSequence="5;6;" Home="1" Sheet="FA01++100+IR01_P1" />
              <Program ID="6" JobSequence="6;" Home="1" Sheet="FA01++100+IR01_P1" />
            </Programs>
            <Tools>
              <Tool ID="1" Type="spotweld gun" Name="FG01" />
              <Tool ID="2" Type="adhesive gun" Name="FG02" />
            </Tools>
            <UserNumbers NumberRequired="True" />
          </Robot>
          <TypePlaceholder Name="" />
        </EM>
      </Station>
    </SA>
    <SA ID="02">
      <Station ID="100">
        <EM ID="02" Name="IR01" IsRobot="TRUE">
          <Robot Name="AR02" Manufacturer="FANUC" RobotIndex="2">
            <Jobs>
              <Job ID="1" Description="Handling Step 1" Type="" />
              <Job ID="2" Description="Handling Step 2" Type="" />
              <Job ID="3" Description="Handling Step 3" Type="" />
              <Job ID="4" Description="Handling Step 4" Type="" />
              <Job ID="5" Description="Handling Step 5" Type="" />
              <Area/>
            </Jobs>
            <Areas>
              <Area ID="1" Description="100TP02" TargetEM_No="" />
              <Area ID="2" Description="100FR01-FX01" TargetEM_No="" />
              <Area ID="3" Description="100FX01" TargetEM_No="" />
            </Areas>
            <Userbits>
              <Userbit ID="1" Description="Userbit1: Pick_Action">
                <Reference Area="2" Job="4" />
              </Userbit>
              <Userbit ID="2" Description="Userbit2: Drop_Action">
                <Reference Area="1" Job="1" />
                <Reference Area="1" Job="2" />
                <Reference Area="2" Job="3" />
              </Userbit>
              <Userbit ID="30" Description="xx_Mute_Sensors">
                <Reference Area="2" Job="1" />
                <Reference Area="1" Job="1" />
                <Reference Area="1" Job="2" />
                <Reference Area="2" Job="2" />
                <Reference Area="2" Job="3" />
                <Reference Area="2" Job="4" />
                <Reference Area="3" Job="5" />
              </Userbit>
              <Userbit ID="31" Description="xx_Type_Transfer">
                <Reference Area="2" Job="1" />
                <Reference Area="1" Job="1" />
                <Reference Area="1" Job="2" />
                <Reference Area="2" Job="2" />
                <Reference Area="2" Job="3" />
                <Reference Area="2" Job="4" />
                <Reference Area="3" Job="5" />
              </Userbit>
            </Userbits>
            <FZones />
            <Programs>
              <Program ID="1" JobSequence="1;2;3;4;5;" Home="1" Sheet="FA01++100+IR02_P1" />
              <Program ID="2" JobSequence="2;3;4;5;" Home="1" Sheet="FA01++100+IR02_P1" />
              <Program ID="3" JobSequence="3;4;5;" Home="1" Sheet="FA01++100+IR02_P1" />
              <Program ID="4" JobSequence="4;5;" Home="1" Sheet="FA01++100+IR02_P1" />
              <Program ID="5" JobSequence="5;" Home="1" Sheet="FA01++100+IR02_P1" />
            </Programs>
            <Tools>
              <Tool ID="1" Type="gripper" Name="FG01" />
            </Tools>
            <UserNumbers NumberRequired="True" />
          </Robot>
          <TypePlaceholder Name="Type" />
        </EM>
        <EM ID="03" Name="IR03" IsRobot="TRUE">
          <Robot Name="AR03" Manufacturer="FANUC" RobotIndex="3">
            <Jobs>
              <Job ID="1" Description="Tackweld Step 1" Type="" />
              <Job ID="2" Description="Tackweld Step 2" Type="" />
              <Job ID="3" Description="Tackweld Step 3" Type="" />
              <Job ID="4" Description="Tackweld Step 4" Type="" />
              <Job ID="5" Description="Tackweld Step 5" Type="" />
              <Job ID="6" Description="Tackweld Step 6" Type="" />
              <Job ID="7" Description="Tackweld Step7" Type="" />
            </Jobs>
            <Areas>
              <Area ID="1" Description="100FR01-FX01" TargetEM_No="" />
              <Area ID="2" Description="100FR02-FX01" TargetEM_No="" />
            </Areas>
            <Userbits />
            <FZones />
            <Programs>
              <Program ID="1" JobSequence="1;2;3;4;5;6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="2" JobSequence="2;3;4;5;6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="3" JobSequence="3;4;5;6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="4" JobSequence="4;5;6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="5" JobSequence="5;6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="6" JobSequence="6;7;" Home="1" Sheet="FA01++100+IR03_P1" />
              <Program ID="7" JobSequence="7;" Home="1" Sheet="FA01++100+IR03_P1" />
            </Programs>
            <Tools>
              <Tool ID="1" Type="spotweld gun" Name="GW01" />
            </Tools>
            <UserNumbers NumberRequired="False" />
          </Robot>
        </EM>
      </Station>
    </SA>
  </PLC>
  <ImportDocuments>
    <HandshakeDocument Name="DO30011_FA01_Robot_PLC_Handshake_v6" ImportDate="18/04/2024" />
  </ImportDocuments>
</Project>

Solution

  • You can express this with Schematron and XSLT/XPath 2 or later, I think e.g.

    <schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt3">
        <pattern>
            <rule context="PLC">
                <assert 
                  test="every $station1 in .//Station satisfies
                        every $station2 in .//Station[not($station1 is .) and $station1/@ID = @ID] satisfies 
                        not($station1/EM/@Name = $station2/EM/@Name)">duplicate Names</assert>
            </rule>
        </pattern>
    </schema>
    

    Or you can use XSD 1.1 with assertions e.g. with a schema like

    <?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" elementFormDefault="qualified"
        vc:minVersion="1.1">
        
        <xs:element name="Project">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="PLC" maxOccurs="unbounded">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="Type">
                                    <xs:complexType>
                                        <xs:sequence>
                                            <xs:element name="TypeDef">
                                                <xs:complexType>
                                                    <xs:attribute name="ID" type="xs:integer"/>
                                                    <xs:attribute name="Name" type="xs:string"/>
                                                    <xs:attribute name="Description" type="xs:string"/>
                                                </xs:complexType>
                                            </xs:element>
                                        </xs:sequence>
                                    </xs:complexType>
                                </xs:element>
                                <xs:element name="SA" maxOccurs="unbounded">
                                    <xs:complexType>
                                        <xs:sequence>
                                            <xs:element name="Station">
                                                <xs:complexType>
                                                    <xs:sequence>
                                                        <xs:element name="EM" maxOccurs="unbounded">
                                                            <xs:complexType>
                                                                <xs:attribute name="ID" type="xs:integer"/>
                                                                <xs:attribute name="Name" type="xs:string"/>
                                                                <xs:attribute name="IsRobot" type="xs:string"/>
                                                            </xs:complexType>
                                                        </xs:element>
                                                    </xs:sequence>
                                                    <xs:attribute name="ID" type="xs:integer"/>
                                                </xs:complexType>
                                            </xs:element>                                        
                                        </xs:sequence>
                                        <xs:attribute name="ID" type="xs:integer"/>
                                    </xs:complexType>
                                </xs:element>
                            </xs:sequence>
                            <xs:attribute name="Name" type="xs:string"/>
                            <xs:assert id="no-duplicate-names" 
                                test="every $station1 in .//Station satisfies
                                      every $station2 in .//Station[not($station1 is .) and $station1/@ID = @ID] satisfies 
                                      not($station1/EM/@Name = $station2/EM/@Name)"/>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:complexType>
        </xs:element>  
        
    </xs:schema>
    

    an instance like

    <?xml version="1.0" encoding="UTF-8"?>
    <Project>
        <PLC Name="PLC">
            <Type>
                <TypeDef ID="1" Name="G05" Description="" />
            </Type>
            <SA ID="01">
                <Station ID="100">
                    <EM ID="01" Name="IR01" IsRobot="TRUE"></EM>
                </Station>
            </SA>
            <SA ID="02">
                <Station ID="100">
                    <EM ID="02" Name="IR04" IsRobot="TRUE"></EM>
                    <EM ID="03" Name="IR03" IsRobot="TRUE"></EM>
                </Station>
            </SA>
        </PLC>
    </Project>
    

    should be valid while an instance like

    <?xml version="1.0" encoding="UTF-8"?>
    <Project>
        <PLC Name="PLC">
            <Type>
                <TypeDef ID="1" Name="G05" Description="" />
            </Type>
            <SA ID="01">
                <Station ID="100">
                    <EM ID="01" Name="IR01" IsRobot="TRUE"></EM>
                </Station>
            </SA>
            <SA ID="02">
                <Station ID="100">
                    <EM ID="02" Name="IR01" IsRobot="TRUE"></EM>
                    <EM ID="03" Name="IR03" IsRobot="TRUE"></EM>
                </Station>
            </SA>
        </PLC>
    </Project>
    

    is invalid (and e.g. SaxonEE would tell you

    Validation error on line 3 column 21 of names-invalid.xml:
      FORG0001: Element PLC does not satisfy assertion every $station1 in .//Station satisfies
      every $station2 in .//Station[not($station1 is .) and $station1/@ID = @ID] satisfies
      not($station1/EM/@Name = $station2/EM/@Name)
      See https://www.w3.org/TR/xmlschema11-1/#sec-cvc-assertion clause 0
      Nodes for which the assertion fails:
      * element(Station) at PLC/SA[1]/Station[1]
      * element(Station) at PLC/SA[2]/Station[1]
    

    )

    XSD 1.1 is support by at least two open-source libraries (Apache Xerces Java https://xerces.apache.org/xerces2-j/, Python XMLSchema https://pypi.org/project/xmlschema/) and various commercial libraries like SaxonEE or AltovaXML.

    A sample .NET 8 console application using the Python library XmlSchema with the PythonNet package is online at https://github.com/martin-honnen/PythonNETXmlSchemaTest1.