c# - IXmlSerialized 根据架构进行验证

标签 c# xml serialization xsd schema

我正在实现IXmlSerializable用于我的类的自定义(反)序列化逻辑,但希望根据 XSD 架构检查 XML 的读写。我添加了 XmlSchemaProviderAttribute :

[XmlSchemaProvider("ConfigSchema")]
[XmlRoot("Config")]
public class Config
{
    // properties, fields and methods incl. interface methods

    public static XmlQualifiedName ConfigSchema(XmlSchemaSet xs)
    {
        const string xsdPath = "./Config.xsd";

        var serializer = new XmlSerializer(typeof(XmlSchema));
        var schema = (XmlSchema)serializer.Deserialize(new XmlTextReader(xsdPath), null);

        xs.XmlResolver = new XmlUrlResolver();
        xs.Add(schema);

        return new XmlQualifiedName("Config", "namespace");
    }
}

架构加载良好,并且(反)序列化按预期工作,但没有验证。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="ConfigSchema" 
    targetNamespace="namespace"
    elementFormDefault="qualified"
    xmlns="namespace"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="Config">
        <xs:all>
            <xs:element name="Config">
                <xs:complexType>
                    <xs:all>
                        <xs:element name="name" type="xs:string" />
                        <xs:element name="timeout" type="xs:time" />
                        <xs:element name="points" minOccurs="1">
                            <xs:complexType>
                                <xs:sequence>
                                    <xs:element name="point" minOccurs="1" maxOccurs="unbounded">
                                        <xs:complexType>
                                            <xs:all>
                                                <xs:element name="a" type="xs:int" />
                                                <xs:element name="b" type="xs:int" />
                                                <xs:element name="c" type="xs:int" />
                                            </xs:all>
                                        </xs:complexType>
                                    </xs:element>
                                </xs:sequence>
                            </xs:complexType>
                        </xs:element>
                    </xs:all>
                </xs:complexType>
            </xs:element>
        </xs:all>
    </xs:complexType>
</xs:schema>

如果我针对上述架构反序列化以下内容,则不会引发异常(<timeout> 丢失,但在架构中的 <xs:all> 下指定):

<?xml version="1.0" encoding="utf-8" ?>
    <Config
        xmlns:xsi="http://w3.org/2001/XMLScehma-instance"
        xsi:schemaLocation="namespace Config.xsd">
        <name>some name</name>
        ...

编辑:这是我的运行方式

string path = "./serviceconfig.xml";
var serializer = new XmlSerializer(typeof(Config));
var cfg = (Config)serializer.Deserialize(new XmlTextReader(path), null);

根据架构验证传入/传出 XML 的“正确”/“最佳”方法是什么?

编辑#2:更多信息

这是完整的 XML

<?xml version="1.0" encoding="utf-8" ?>
    <Config
        xmlns:xsi="http://w3.org/2001/XMLScehma-instance"
        xsi:schemaLocation="namespace Config.xsd">
        <name>some name</name>
        <timeout>10</timeout>
        <points>
            <point>
                <a>5</a>
                <b>7</b>
                <c>11</c>
            </point>
            <point>
                <a>8</a>
                <b>7</b>
                <c>3</c>
            </point>
        </points>
    </Config>

我尝试查看 ReadXml(XmlReader reader) 中的 XmlReaderSettings以下内容没有帮助

var settings = new XmlReaderSettings
{
    ValidationType = ValidationType.Schema,
    Schemas = _schemaSet
};

settings.ValidationEventHandler += (sender, args) => Console.WriteLine(args.Message);
reader = XmlReader.Create(reader, settings);

_schema从静态 ConfigSchema() 设置如上所述。

最佳答案

XML 未验证,因为您的架构指定了 targetNamespace = "namespace",但您的 XML 实例未使用 xmlns 引用此命名空间。

因此验证器不知道如何验证您的 XML,因为它没有意识到您的 XML 使用架构中定义的类型。

如果您发布完整的架构和 xml 实例,我将能够制作一个工作示例。

更新

感谢您发布您的架构。你在哪里得到它?我问的原因是它没有定义任何根节点,只是一个名为 Config 的类型。

如果删除外部复杂类型元素:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="ConfigSchema"
    targetNamespace="namespace"
    elementFormDefault="qualified"
    xmlns="namespace"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Config">
    <xs:complexType>
      <xs:all>
        <xs:element name="name" type="xs:string" />
        <xs:element name="timeout" type="xs:time" />
        <xs:element name="points" minOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="point" minOccurs="1" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:all>
                    <xs:element name="a" type="xs:int" />
                    <xs:element name="b" type="xs:int" />
                    <xs:element name="c" type="xs:int" />
                  </xs:all>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:all>
    </xs:complexType>
  </xs:element>
</xs:schema>

我能够验证以下实例:

<?xml version="1.0" encoding="utf-8" ?>
<Config xmlns="namespace">
  <name>some name</name>
  <timeout>13:20:00.000-05:00</timeout>
  <points>
    <point>
      <a>5</a>
      <b>7</b>
      <c>11</c>
    </point>
    <point>
      <a>8</a>
      <b>7</b>
      <c>3</c>
    </point>
  </points>
</Config>

请注意,根据架构,“10”不是超时列的有效值。当我尝试时,出现此错误:

The 'namespace:timeout' element is invalid - The value '10' is invalid according to its datatype 'http://www.w3.org/2001/XMLSchema:time' - The string '10' is not a valid XsdDateTime value.

关于c# - IXmlSerialized 根据架构进行验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21284592/

相关文章:

xml - XPath 如何处理 XML 命名空间?

xml - 单击后更改按钮中的图像?

c# - MEF,延迟加载高级元数据和序列化异常

Javascript:stringify对象(包括类型函数的成员)

c# - 带有 v4 Webchat channel 的 Bot 框架问候消息

C# 编码风格 - 行长/换行

c# - wpf 绑定(bind)到另一个 xaml 文件中的元素

c# - 覆盖现有的 XML 文件(如果它已经存在)

c# - 使用 RestSharp 反序列化 XML 文档时出错

java - 在序列化和反序列化过程中如何调用构造函数?