【问题标题】:IXmlSerializable Validate Against SchemaIXmlSerializable 针对架构进行验证
【发布时间】:2014-02-12 14:37:07
【问题描述】:

我正在为我的类的自定义(反)序列化逻辑实现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>

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

<?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。
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。

标签: c# xml serialization xsd schema


【解决方案1】:

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”不是超时列的有效值。当我尝试时,我得到了这个错误:

'namespace:timeout' 元素无效 - 值 '10' 无效 根据其数据类型'http://www.w3.org/2001/XMLSchema:time' - 字符串“10”不是有效的 XsdDateTime 值。

【讨论】:

  • 我添加了 &lt;Config xmlns="namespace" ... 但这引发了反序列化异常:“ 不是预期的。”
  • 谢谢。我自己做的。最初我没有包装 &lt;xs:complexType&gt; 但是我的 XmlSerializer 抱怨命名空间的未知类型“配置”......添加 complexType 标签解决了这个问题。您能否分享您的 C# 代码以及您如何验证/反序列化 XML 以获得完整的图片,谢谢。
  • 我没有写任何代码——只是使用了一个免费工具utilities-online.info/xsdvalidation
【解决方案2】:

经过大量挖掘并在 Hugh 的回答的帮助下,我能够破解这个难题。

  1. 我将命名空间添加到我的 XML 和 C# 类中:

    <?xml version="1.0" encoding="utf-8" ?>
    <Config xlmns="namespace" ...
    

    [XmlSchemaProvider("ConfigSchema")]
    [XmlRoot(Namespace="namespace", ElementName="Config")]
    public class Config : IXmlSerializable
    {
       private static XmlSchemaSet _schema;
    
       public static XmlQualifiedName ConfigSchema(XmlSchemaSet xs)
       {
          _schema = xs;
          // rest of method as OP
       }
    
       public void ReadXml(XmlReader reader)
       {
          var settings = new XmlReaderSettings
          {
             ValidationType = ValidationType.Schema,
             Schemas = _schemas;
          }
    
          settings.ValidationEventHandler += ValidationCallBack;
          reader = XmlReader.Create(reader, settings);
          reader.Read(); // your own read logic
       }
    
       // rest of class
    }
    
  2. 我的 XSD 完全错了。我将类型定义与元素结构定义混淆了。

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

【讨论】:

  • 我必须说,我发现您基本上将我的答案整理成您自己的答案然后将其授予您自己,这有点不正常。上面的架构在语义上与我发布的架构相同,XML 也是如此。当然,您需要使您的序列化代码正常工作,但该特定解决方案可以表示为对您原始帖子的修改或对我的评论。不太确定还能说什么。
  • 您的回复非常有帮助,但它并没有解决问题,因为它纯粹是在查看 XML(我在一开始就提到了您的积极贡献)。一个完整的答案需要更多的 C#,因为我的问题不是如何为我的 XML 编写有效的模式,而是如何通过 C# 验证它。无论如何,对自己知道任何事情不感兴趣,所以请随意取消标记它或取消标记,如果这让你感觉更好。这个答案是我的问题的“完整解决方案”(就我的理解而言),因为它涵盖了 XML、XSD 和 C#。
猜你喜欢
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
相关资源
最近更新 更多