XmlSchemaValidationException:这是一个无效的 xsi:type 'Book' 尝试反序列化使用 XSD 架构验证它的 XML 时

Posted

技术标签:

【中文标题】XmlSchemaValidationException:这是一个无效的 xsi:type \'Book\' 尝试反序列化使用 XSD 架构验证它的 XML 时【英文标题】:XmlSchemaValidationException: This is an invalid xsi:type 'Book' when trying to deserialize an XML validating it with an XSD schemaXmlSchemaValidationException:这是一个无效的 xsi:type 'Book' 尝试反序列化使用 XSD 架构验证它的 XML 时 【发布时间】:2021-12-30 19:07:56 【问题描述】:

我有一个包含 LibraryAssets 数组的 xml,它们是书籍、报纸和专利,而 LibraryAsset 是它们派生的抽象类。 我使用 Visual Studio 的 Create 架构基于该 xml 创建了一个 xsd 架构。 但是当我尝试反序列化验证它是否与架构匹配的 xml 时,我收到以下错误:

System.InvalidOperationException : There is an error in XML document (3, 4).
  ----> System.Xml.Schema.XmlSchemaValidationException : This is an invalid xsi:type 'Book'.
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)

我的 xsd 架构:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           attributeFormDefault="unqualified"
           elementFormDefault="qualified">
    <xsd:element name="ArrayOfLibraryAsset">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element maxOccurs="unbounded" name="LibraryAsset">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="Id" type="xsd:unsignedInt" />
                            <xsd:element name="Name" type="xsd:string" />
                            <xsd:element name="YearPublished" type="xsd:unsignedShort" />
                            <xsd:element name="PagesNumber" type="xsd:unsignedByte" />
                            <xsd:element name="Annotation" type="xsd:string" />
                            <xsd:element name="Price" type="xsd:unsignedByte" />
                            <xsd:element minOccurs="0" name="Number" type="xsd:string" />
                            <xsd:element minOccurs="0" name="Inventors">
                                <xsd:complexType>
                                    <xsd:sequence>
                                        <xsd:element name="string" type="xsd:string" />
                                    </xsd:sequence>
                                </xsd:complexType>
                            </xsd:element>
                            <xsd:element minOccurs="0" name="Country" type="xsd:string" />
                            <xsd:element minOccurs="0" name="ApplicationDate" type="xsd:dateTime" />
                            <xsd:element minOccurs="0" name="StandardNumber" type="xsd:string" />
                            <xsd:element minOccurs="0" name="Authors">
                                <xsd:complexType>
                                    <xsd:sequence>
                                        <xsd:element name="string" type="xsd:string" />
                                    </xsd:sequence>
                                </xsd:complexType>
                            </xsd:element>
                            <xsd:element minOccurs="0" name="CityPublished" type="xsd:string" />
                            <xsd:element minOccurs="0" name="Publisher" type="xsd:string" />
                            <xsd:element minOccurs="0" name="CopiesNumber" type="xsd:unsignedShort" />
                            <xsd:element minOccurs="0" name="Issue" type="xsd:unsignedByte" />
                            <xsd:element minOccurs="0" name="IssueDate" type="xsd:dateTime" />
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xs:schema>

Xml 文件:

<?xml version="1.0"?>
<ArrayOfLibraryAsset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <LibraryAsset xsi:type="Book">
    <Id>62915385</Id>
    <Name>Unspecified</Name>
    <YearPublished>2000</YearPublished>
    <PagesNumber>200</PagesNumber>
    <Annotation>No annotation.</Annotation>
    <Price>50</Price>
    <StandardNumber>000-0-00-000000-0</StandardNumber>
    <Authors>
      <string>Author</string>
    </Authors>
    <CityPublished>Unspecified</CityPublished>
    <Publisher>Unspecified</Publisher>
    <CopiesNumber>300</CopiesNumber>
  </LibraryAsset>
  <LibraryAsset xsi:type="Newspaper">
    <Id>57188600</Id>
    <Name>Unspecified</Name>
    <YearPublished>2021</YearPublished>
    <PagesNumber>25</PagesNumber>
    <Annotation>No annotation.</Annotation>
    <Price>5</Price>
    <StandardNumber>0000-0000</StandardNumber>
    <CityPublished>Unspecified</CityPublished>
    <Publisher>Unspecified</Publisher>
    <CopiesNumber>1500</CopiesNumber>
    <Issue>10</Issue>
    <IssueDate>2021-11-19T00:00:00+04:00</IssueDate>
  </LibraryAsset>
  <LibraryAsset xsi:type="Patent">
    <Id>14464371</Id>
    <Name>Unspecified</Name>
    <YearPublished>2021</YearPublished>
    <PagesNumber>50</PagesNumber>
    <Annotation>No annotation.</Annotation>
    <Price>10</Price>
    <Number>X0000000</Number>
    <Inventors>
      <string>Inventor</string>
    </Inventors>
    <Country>Unspecified</Country>
    <ApplicationDate>2021-11-19T00:00:00+04:00</ApplicationDate>
    <IssueDate>2021-11-18T19:34:16.5902406+04:00</IssueDate>
  </LibraryAsset>
</ArrayOfLibraryAsset>

Xml 反序列化:

var schemas = new XmlSchemaSet();
schemas.Add(null, shemaFilePath);
Exception exception = null;
var settings = new XmlReaderSettings

    Schemas = schemas,
    ValidationType = ValidationType.Schema,
    ValidationFlags =
        XmlSchemaValidationFlags.ProcessIdentityConstraints |
        XmlSchemaValidationFlags.ReportValidationWarnings
;
settings.ValidationEventHandler += delegate (object sender, ValidationEventArgs args)

    if (args.Severity == XmlSeverityType.Warning)
    
        _log.Warning(args.Message);
    
    else
    
        exception ??= args.Exception;
        _log.Error(exception);
        throw exception;
    
;
using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var xmlReader = XmlReader.Create(fileStream, settings);
var xmlSerializer = new XmlSerializer(typeof(List<T>));
data = xmlSerializer.Deserialize(xmlReader) as List<T>;

【问题讨论】:

你说你有一个抽象的抽象类型 libraryassets 是抽象的。你的 XSD 告诉了一些不同的东西,它只是它有一个复杂的类型 LibraryAssets,它不知道这本书是从哪里派生的? @Aldert 那我该怎么说呢?我项目中的 LibraryAsset 类有一个标签 [XmlInclude(typeof(Book))]。如果我也应该在 xsd 中添加一些东西,那会是什么? 【参考方案1】:

解决方案比我想象的要简单得多。

所以,基本上,我只需要声明每种类型(书籍、报纸、专利是抽象 LibraryAsset 的扩展)。最终解决方案 XSD 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           attributeFormDefault="unqualified"
           elementFormDefault="qualified">
    <xs:element name="LibraryAsset" type="LibraryAsset" abstract="true"/>
    <xs:element name="Book" type="Book"/>
    <xs:element name="Newspaper" type="Newspaper"/>
    <xs:element name="Patent" type="Patent"/>

    <xsd:complexType name="LibraryAsset" abstract="true">
        <xsd:sequence>
            <xsd:element name="Id" type="xsd:int" />
            <xsd:element name="Name" type="xsd:string" />
            <xsd:element name="YearPublished" type="xsd:int" />
            <xsd:element name="PagesNumber" type="xsd:int" />
            <xsd:element name="Annotation" type="xsd:string" />
            <xsd:element name="Price" type="xsd:int" />
            <xsd:element minOccurs="0" name="Number" type="xsd:string" />
            <xsd:element minOccurs="0" name="Inventors">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="string" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element minOccurs="0" name="Country" type="xsd:string" />
            <xsd:element minOccurs="0" name="ApplicationDate" type="xsd:dateTime" />
            <xsd:element minOccurs="0" name="StandardNumber" type="xsd:string" />
            <xsd:element minOccurs="0" name="Authors">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="string" type="xsd:string" />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            <xsd:element minOccurs="0" name="CityPublished" type="xsd:string" />
            <xsd:element minOccurs="0" name="Publisher" type="xsd:string" />
            <xsd:element minOccurs="0" name="CopiesNumber" type="xsd:int" />
            <xsd:element minOccurs="0" name="Issue" type="xsd:int" />
            <xsd:element minOccurs="0" name="IssueDate" type="xsd:dateTime" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="Book">
        <xsd:complexContent>
            <xsd:extension base="LibraryAsset">

            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="Newspaper">
        <xsd:complexContent>
            <xsd:extension base="LibraryAsset">

            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="Patent">
        <xsd:complexContent>
            <xsd:extension base="LibraryAsset">

            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:element name="ArrayOfLibraryAsset">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element minOccurs="0" maxOccurs="unbounded" name="LibraryAsset">
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xs:schema>

【讨论】:

【参考方案2】:

因此,您的模式生成器有一个限制,即忽略 xsi:type 属性。这并不奇怪,很难知道它会对它们做什么。

您显然知道该工具不知道的一些东西(“LibraryAssets 是书籍、报纸和专利,LibraryAsset 是它们派生自的抽象类”),并且通常的做法是,当您生成架构时,您得到的只是第一次剪辑,您应该根据您对应用程序域语义的了解对其进行编辑。

【讨论】:

@Michael_Kay 我正在努力寻找在这种情况下该怎么做,但我仍然没有成功。也许你可以给我一个提示,告诉我如何让它知道我的期望?我试图命名元素 Book 而不是 LibraryAsset 并向其添加 ,但随后它显示“元素 'ArrayOfLibraryAsset' 的子元素 'LibraryAsset' 无效。预期的可能元素列表:'书籍、报纸、专利”。” 如果您只想让您的文档通过验证,那么定义三种类型 Books、Newspapers 和 Patents,它们是 LibraryAsset 复杂类型的琐碎限制(需要成为命名的全局类型)。 @Michael_Kay 我不完全明白你的意思是让它们成为微不足道的限制,你能详细说明一下吗?对不起,我昨天才开始学习xsd模式。 对不起,这个网站是为了回答具体问题,而不是提供入门教程。 XSD 不容易掌握(我至少花了六周时间),我建议阅读 Priscilla Walmsley 的书。

以上是关于XmlSchemaValidationException:这是一个无效的 xsi:type 'Book' 尝试反序列化使用 XSD 架构验证它的 XML 时的主要内容,如果未能解决你的问题,请参考以下文章