我正在为我的类的自定义(反)序列化逻辑实现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");
}
}
架构加载正常,(de)序列化按预期工作,但没有验证。
<?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);
根据架构验证incomming / outgoing 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()
设置的。
答案 0 :(得分:4)
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值。
答案 1 :(得分:1)
经过多次挖掘并在Hugh的答案帮助下,我能够破解这个坚果。
我将命名空间添加到我的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
}
我的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>