为了解释 Heinzi 的回答,我需要更改默认命名空间(从技术上讲,是根元素的命名空间),这样我就可以使用XmlAttributeOverrides
应用于我无法控制的类层次结构来反序列化文档。作为其中的一部分,我必须为XmlRootAttribute
第一类分配一个属性。问题在于,为了反序列化文档,XmlSerializer
期望 Namespace 值与 的命名空间匹配XmlRootAttribute
,这是无法保证的。
使用以下派生自 的类,XmlReader
可以为反序列化程序为根元素的命名空间分配一个已知值。可以强制读取器的命名空间与XmlRootAttribute
属性的命名空间匹配(即使它是空字符串)。
简化解决方案是使用XmlWrappingReader
Alterant 在 StackOverflow 上的回答到How do I create a XmlTextReader that ignore Namespaces and does not check characters。
/// <summary>
/// XML document reader replaces the namespace of the root element.
/// </summary>
public class MyXmlReader : Mvp.Xml.Common.XmlWrappingReader
{
// Namespace of the document's root element. Read from document.
private string rootNamespace = "";
/// <summary>
/// Get or set the target namespace to use when deserializing.
/// </summary>
public string TargetNamespace { get; set; }
/// <summary>
/// Initialize a new instance of the MXmlReader class.
/// </summary>
/// <param name="reader">XmlReader instance to modify.</param>
public MyXmlReader(XmlReader reader) : base(reader)
{
TargetNamespace = "";
}
/// <summary>
/// Return the namespace of the XML node. Substitute the target namespace if it matches the namespace of the root element.
/// </summary>
public override string NamespaceURI
{
get
{
if (Depth == 0 && NodeType == XmlNodeType.Element)
{
// Save the namespace from the document's root element.
rootNamespace = base.NamespaceURI;
}
if (base.NamespaceURI == rootNamespace)
{
// Substitute the schema's targetNamespace for the root namespace.
return TargetNamespace;
}
// Use the native namespace of the XML node.
return base.NamespaceURI;
}
}
}
我实例化了 MyXmlReader 并使用它反序列化到标记为的对象XmlRootAttribute(ElementName = "DocumentRoot", Namespace = "http://my.target.namespace")
:
var reader = new MyXmlReader(XmlReader.Create(stream));
reader.TargetNamespace = "http://my.target.namespace";
// Deserialize using the defined XML attribute overrides that can
// supply XML serialization attributes to types at runtime.
Type t = typeof(SomeDeserializedObject);
var xo = SomeDeserializedObject.GetXmlAttributeOverrides();
XmlSerializer serializer = new XmlSerializer(t, xo);
SomeDeserializedObject o = (SomeDeserializedObject)serializer.Deserialize(reader);
如果我导入的 XML 文档有不同的根命名空间,或者根本没有指定一个,现在我仍然可以反序列化它。