XmlSchemaValidationException:当尝试反序列化 XML 并使用 XSD 模式验证它时,这是无效的 xsi:type 'Book'

XmlSchemaValidationException: This is an invalid xsi:type 'Book' when trying to deserialize an XML validating it with an XSD schema

我有一个 xml 和一组 LibraryAssets,它们是书籍、报纸和专利,而 LibraryAsset 是它们派生的抽象 class。 我使用 visual studio 的创建模式基于 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>;

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

您显然知道该工具不了解的内容(“LibraryAssets 是书籍、报纸和专利,而 LibraryAsset 是它们的抽象 class”)并且通常的做法是,当您生成架构时,您得到的只是第一次剪辑,您需要对其进行编辑以考虑您对应用程序域语义的了解。

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

所以,基本上,我只需要声明每种类型(书籍、报纸、专利是抽象 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>