在没有名称空间的情况下反序列化XML,但在期望名称空间的类中反序列化

重复:
在序列化对象时省略所有xml命名空间? 不一样..我想用另一种方式:反序列化!


我有一个C#类如下:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.portalfiscal.inf.br/nfe")] [System.Xml.Serialization.XmlRootAttribute("NFe", Namespace = "http://www.portalfiscal.inf.br/nfe", IsNullable = false)] public partial class TNFe { private TNFeInfNFe infNFeField; private SignatureType signatureField; ///  public TNFeInfNFe infNFe { ... 

我使用此类来按用户请求序列化/反序列化XML文件。 但是我遇到了一个问题:在这个软件的新版本中添加了名称空间定义。 XML仍然是相同的,只添加名称空间定义。

例如,最后一个版本……

    ... 

和新版本……

    ... 

我需要加载带有和不带这些名称空间的XML文件。 我有很多嵌套类,每个嵌套类都有自己的命名空间定义。

我想对两个XML使用相同的类,有和没有名称空间。

我试图创建一个XmlTextReader并覆盖NamespaceURI方法,但我仍然收到一个没有太多信息的exception。 我认为.NET引擎正在尝试针对XML强制类命名空间定义。

我遇到了类似的代理类挑战。 由于我不打算进入的原因,我需要使用Web服务器上的XmlSerializer手动序列化类并在客户端上反序列化。 我无法在线找到优雅的解决方案,因此我在Visual Studio中自动生成XmlTypeAttribute之后手动删除了XmlTypeAttribute,从而避免了这个问题。

我一直回过头来看看是否有办法让命名空间进行锻炼。 以下是我如何在不需要修改自动生成的类的情况下工作。 我最终使用XmlTextReader在匹配属性名称的节点上返回所需的命名空间。 还有改进的余地,但我希望它有所帮助。

 class Program { static void Main(string[] args) { //create list to serialize Person personA = new Person() { Name = "Bob", Age = 10, StartDate = DateTime.Parse("1/1/1960"), Money = 123456m }; List listA = new List(); for (int i = 0; i < 10; i++) { listA.Add(personA); } //serialize list to file XmlSerializer serializer = new XmlSerializer(typeof(List)); XmlTextWriter writer = new XmlTextWriter("Test.xml", Encoding.UTF8); serializer.Serialize(writer, listA); writer.Close(); //deserialize list from file serializer = new XmlSerializer(typeof(List)); List listB; using (FileStream file = new FileStream("Test.xml", FileMode.Open)) { //configure proxy reader XmlSoapProxyReader reader = new XmlSoapProxyReader(file); reader.ProxyNamespace = "http://myappns.com/"; //the namespace of the XmlTypeAttribute reader.ProxyType = typeof(ProxysNamespace.Person); //the type with the XmlTypeAttribute //deserialize listB = (List)serializer.Deserialize(reader); } //display list foreach (ProxysNamespace.Person p in listB) { Console.WriteLine(p.ToString()); } Console.ReadLine(); } } public class Person { public string Name { get; set; } public int Age { get; set; } public DateTime StartDate { get; set; } public decimal Money { get; set; } } namespace ProxysNamespace { [XmlTypeAttribute(Namespace = "http://myappns.com/")] public class Person { public string Name { get; set; } public int Age { get; set; } public DateTime Birthday { get; set; } public decimal Money { get; set; } public override string ToString() { return string.Format("{0}:{1},{2:d}:{3:c2}", Name, Age, Birthday, Money); } } } public class XmlSoapProxyReader : XmlTextReader { List propNames; public XmlSoapProxyReader(Stream input) : base(input) { propNames = new List(); } public string ProxyNamespace { get; set; } private Type proxyType; public Type ProxyType { get { return proxyType; } set { proxyType = value; PropertyInfo[] properties = proxyType.GetProperties(); foreach (PropertyInfo p in properties) { propNames.Add(p.Name); } } } public override string NamespaceURI { get { object localname = LocalName; if (propNames.Contains(localname)) return ProxyNamespace; else return string.Empty; } } } 

为了在没有命名空间的情况下反序列化XML,请将XmlRoot属性添加到表示层次结构顶部的类中:

 [XmlRoot(ElementName="plugins", Namespace="")] 

在我的例子中,Xml没有命名空间,并且开始就像

 <... 

它反序列化的类:

 [XmlRoot(ElementName="plugins", Namespace="")] public class Plugins { //... } 

显然,您的情况可能略有不同,但此代码适用于我:

 using (FileStream stream = File.Open(filePath, FileMode.Open)) { XmlReader reader = new XmlTextReader(stream); XmlSerializer serializer = new XmlSerializer(typeof(Plugins)); var plugins = (Plugins)serializer.Deserialize(reader); } 

-Stan

您可以以文本forms读取文件,删除有问题的命名空间文本,然后对其进行反序列化。

您可能需要将“好”文本写回[memory / string / etc]流,以便可以调用XmlSerializer的Deserialize。

您需要实现IXmlSerializable以改进自定义序列化。