使用 C# 进行 XML 验证

Posted

技术标签:

【中文标题】使用 C# 进行 XML 验证【英文标题】:XML validation with C# 【发布时间】:2021-08-01 12:07:04 【问题描述】:

大家好! 我在尝试根据其架构验证 XML 文件时遇到一些问题。 我拥有的 XML 文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<game:gameXML xmlns:game="national:game" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Header>
    <From description="Gamer">Gamer</From>
    <To description="Player">Player</To>
    <MessageId>1620711716</MessageId>
    <MessageDate>2021-05-11T15:41:53</MessageDate>
    <TransactionGroup>Ball</TransactionGroup>
    <Priority>Medium</Priority>
    <SecurityContext>CONTACT_PERSON_GOES_HERE</SecurityContext>
    <Market>Japan</Market>
  </Header>
  <Transactions>
    <Transaction transaction="1620711716">
      <ReportRequest>
        <ReportParameters xsi:type="game:reportParameters">
          <ReportName>All</ReportName>
          <FromDate>2005-01-01</FromDate>
          <ToDate>2021-05-11</ToDate>    
        </ReportParameters>
      </ReportRequest>
    </Transaction>
  </Transactions>
</game:gameXML>

我使用 VS 2019 生成了相应的架构,这给了我这个:

xmlFile.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:game="national:game" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="national:game" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:import schemaLocation="xmlContent.xsd" />
    <xs:element name="gameXML">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Header" />
                <xs:element ref="Transactions" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

xmlContent.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Header">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="From">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="description" type="xs:string" use="required" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
                <xs:element name="To">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="description" type="xs:string" use="required" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
                <xs:element name="MessageId" type="xs:unsignedInt" />
                <xs:element name="MessageDate" type="xs:dateTime" />
                <xs:element name="TransactionGroup" type="xs:string" />
                <xs:element name="Priority" type="xs:string" />
                <xs:element name="SecurityContext" type="xs:string" />
                <xs:element name="Market" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="Transactions">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Transaction">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="ReportRequest">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="ReportParameters">
                                            <xs:complexType>
                                                <xs:sequence>
                                                    <xs:element name="ReportName" type="xs:string" />
                                                    <xs:element name="FromDate" type="xs:date" />
                                                    <xs:element name="ToDate" type="xs:date" />
                                                </xs:sequence>
                                            </xs:complexType>
                                        </xs:element>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                        <xs:attribute name="transaction" type="xs:unsignedInt" use="required" />
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

我用来加载这些的代码是:

XmlReaderSettings settings = new XmlReaderSettings  DtdProcessing = DtdProcessing.Parse ;
XmlSchemaSet xs = new XmlSchemaSet();
xs.Add("national:game", "xmlFile.xsd");
xs.Add("national:game", "xmlContent.xsd");
xs.Compile();

我一运行它就会报错:

System.Exception: This is an invalid xsi:type 'national:game:reportParameters'.

显然它将命名空间注入xmlContent.xsd 文件,我不知道需要设置什么来防止这种情况。事实上,这个 .xsd 文件应该有它自己的命名空间(参见实际 .xml 文件中的&lt;ReportParameters xsi:type="game:reportParameters"&gt;)。

任何线索、指示或帮助将不胜感激。 谢谢。

【问题讨论】:

我得到一个完全不同的错误 - System.Xml.Schema.XmlSchemaException: 'The 'Header' element is not declared.' - 这是我第一次尝试运行你的代码的机会。我已经准确地复制了每个代码示例。此外,您提到的作为问题的类型注释在实例文档中,并且您没有提到任何针对已编译的 XmlSchemaSet 进行验证的代码,因此使用给定的信息无法重现这一点。我可以看到 ref="Header" 声明没有被识别,我很感激你提供让你通过的代码。 【参考方案1】:

没有任何类型被命名,因此看起来除了架构内置类型之外,xsi:type 没有有效值,因为所有 complexTypes 都是匿名的。

这是 xsd.exe(用于生成架构的工具)受到限制的一个方面,因为根据定义,如果存在 xsi:type 属性,它必须引用架构声明的某些类型,但生成的架构声明没有命名类型。然而,它的目的是解决歧义,因此同样的工具引入歧义是不合逻辑的。

要解决此问题,请重组 xmlContent.xsd 以全局声明 reportParameters 类型并引用它,即

<xs:element name="ReportParameters" type="game:reportParameters"/>

<xs:complexType name="reportParameters">
...

【讨论】:

谢谢@Tom。但不起作用:System.Xml.Schema.XmlSchemaException:无法从位置“xmlContent.xsd”加载架构-“type”属性的值无效-“game:reportParameters”是“type”的无效值' 属性。此外,“xs:complexType”中不允许使用“name”属性 关于第二个错误,我不知道该告诉你什么,因为我已经使用过很多次了,所以可以 100% 确定它是正确的。也许检查XML Schema spec 是否正确声明了所有元素。我会坚持我的回答原则,即 xsi:type 需要一个命名类型,而模式生成器不够复杂,无法处理这个问题。 第二个错误我不太确定,但看起来这是第一个错误的结果;如果它要引用的 complexType 在某些方面是错误的,那么它不会引用一个有效的名称。

以上是关于使用 C# 进行 XML 验证的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中针对 XSD 模式验证 json 数据

使用C#进行XML文档读取

使用 C# 进行查询验证

可以在运行时使用代码针对 xsd 验证 xml 吗?

为啥 C# 正则表达式信用卡验证函数会使用无效值进行验证? [复制]

使用数据注释在 c# 中进行数据验证