我有一个使用命名空间来帮助反序列化存储在XML中的对象的应用程序。 XML命名空间也是对象所在的C#命名空间。例如,给定以下XML剪辑:
<xml-config xmlns:app="MyAppNS">
<app:Person>
<Name>Bill</Name>
<Car>
<Make>Honda</Make>
<Model>Accord</Model>
</Car>
</app:Person>
<app:Person>
<Name>Jane</Name>
<Car>
<Make>VW</Make>
<Model>Jetta</Model>
</Car>
</app:Person>
<app:Car>
<Make>Audi</Make>
<Model>A6</Model>
</app:Car>
</xml-config>
配置实际上只是一个随机的对象包。如您所见,顶层有Person
和Car
个对象。我使用命名空间在加载时确定对象类型以进行正确的反序列化。以下是加载文档的代码:
public static void LoadFile(String file) {
XmlDocument doc = new XmlDocument();
doc.Load(file);
XmlNode root = doc.DocumentElement;
foreach (XmlNode child in root.ChildNodes) {
if (child.NodeType != XmlNodeType.Element) {
continue;
}
Object obj = LoadObject(child);
// TODO handle object here...
}
}
private static Object LoadObject(XmlNode node) {
Object obj = null;
StringBuilder str = new StringBuilder();
if ((node.Prefix != null) && (node.Prefix != "")) {
str.Append(node.NamespaceURI).Append('.');
}
str.Append(node.LocalName);
Assembly assy = Assembly.GetExecutingAssembly();
Type type = assy.GetType(str.ToString());
XmlSerializer serdes = new XmlSerializer(type);
using (XmlNodeReader reader = new XmlNodeReader(node)) {
obj = serdes.Deserialize(reader);
}
return obj;
}
许多人立即看到了这个问题,但是当使用此代码时,生成的Person
对象为空,但没有错误。让反序列化器填充子元素的唯一方法是对子元素使用相同的命名空间:
<app:Person>
<app:Name>Bill</app:Name>
<app:Car>
<app:Make>Honda</app:Make>
<app:Model>Accord</app:Model>
</app:Car>
</app:Person>
我尝试的唯一其他选项是使用完全限定的类型名称作为元素名称(没有命名空间),但是我没有运气。有没有办法让反序列化器接受XML节点的非前缀子节点?
答案 0 :(得分:0)
我终于找到了一种方法来完成这项工作,修改了here找到的答案。
我创建了一个自定义反序列化器,用于复制起始节点的命名空间:
public class CustomXmlNodeReader : XmlNodeReader {
private String _namespace;
public CustomXmlNodeReader(XmlNode node) : base(node) {
_namespace = node.NamespaceURI;
}
public override String NamespaceURI {
get { return _namespace; }
}
}
使用此阅读器,我可以使用以下内容加载存储的对象:
using (XmlNodeReader reader = new CustomXmlNodeReader(node)) {
obj = serdes.Deserialize(reader);
}
我知道这对于XML来说是一个糟糕的形式(强制应用特定的命名空间),但它非常适合我的需求。在这里回答,以防它帮助其他任何人。