我正在尝试使用 XSD 对两个元素之间的属性组合强制执行唯一性约束。该约束在 Notepad++ 中工作正常,但在我的 C# 应用程序中工作不正常。
我已将以下独特的声明添加到我的 XSD 中:
<xs:unique name="uniqueEMNameParentID">
<xs:selector xpath=".//EM"/>
<xs:field xpath="@Name"/>
<xs:field xpath=".//Station/@ID"/>
</xs:unique>
这是我的 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>
使用 Notepad++ 时,XSD 给出正确的错误:“IR01 是唯一身份约束‘uniqueEMNameParentID’的重复键。”但是,当使用以下代码在 C# 中针对 XSD 验证相同的 XML 时,不会报告错误:
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);
});
}
我的 XML 文档不包含任何命名空间,我的 XSD 不包含目标命名空间,并且 attribute 和 elementformdefault 都设置为非限定。有谁知道它可能是什么?
请注意,我的 XML 有两个属性 ID=100 的 Station 元素。这些元素都有一个子元素 EM,其属性名称 = IR01。这应该是不可能的。
完整的XSD:
<xs:schema attributeFormDefault="qualified" 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>
完整的 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>
我不知道为什么模式处理器之间存在差异,但我确实注意到,在唯一性约束中,从
<xs:field xpath=".//Station/@ID"/>
元素开始时,字段 EM
永远不会选择任何内容,因此它可能不会执行任何操作你是故意的。
我认为XSD 1.0中的规则是,当其中一个字段没有选择任何内容时,则认为满足唯一性约束。然而,在这个领域,模式处理器并不总是 100% 一致。