C#忽略名称空间时反序列化xml

问题描述

我必须加载Xml文件并将其反序列化为对象。我可以阅读xml,到达描述对象的地步,并且仅从那很棒的那一部分解析xml,但是在xml的根中声明了一个命名空间。

我不明白为什么,但是当读取xml时,即使我从给定节点读取xmlns属性,也会将xmlns属性添加到其中,导致由于以下原因,我的程序无法将其反序列化为对象意外的成员。

我的代码

public static SomeClass GetobjectFromXml (string path)
    {
        XmlReader reader = XmlReader.Create(path);
        string wantednodeContents = string.Empty;
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element && reader.Name == "IWantThis")
            {
                wantednodeContents = reader.ReadOuterXml();
                break;
            }
        }
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(SomeClass));
        System.IO.StringReader stringReader = new System.IO.StringReader(wantednodeContents);
        SomeClass loadedSomeClassXml = xmlSerializer.Deserialize(stringReader) as SomeClass;
        return loadedSomeClassXml;
    }

如何摆脱xmlns并将xml反序列化为对象?

解决方法

XDocument在反序列化任何XML时为您提供了更多的灵活性。我有一个类似的问题,可以使用下一个代码段解决:

///Type T must have a default constructor

private T XMLToObject (string pathXML)
{
   T myObjectParsedFromXML= default(T);

   LoadOptions loadOpt = LoadOptions.SetLineInfo;
   XDocument xmlDocument = XDocument.Load(pathXML,loadOpt);

   string namespaceXML = xmlDocument.Root.Name.Namespace.NamespaceName;
   XmlSerializer serializer = new XmlSerializer(typeof(T),defaultNamespace: namespaceXML); 
   
   XmlReader XMLreader = xmlDocument.CreateReader();

   myObjectParsedFromXML= (T)serializer.Deserialize(XMLreader);   
   
   return myObjectParsedFromXML;
}

此外,XmlSerializer为您提供了一组事件,用于注册序列化过程中的任何问题或错误:

 XmlSerializer serializer = new XmlSerializer(typeof(T),defaultNamespace: namespaceXML);
 
 serializer.UnknownAttribute += new XmlAttributeEventHandler((sender,args) =>
            {
                //Your code for manage the errors during serialization
            });

 serializer.UnknownElement += new XmlElementEventHandler((sender,args) =>
            {  
               //Your code for manage the errors during serialization  
            });

,

您在这里遇到一些问题:

  1. 默认名称空间属性被添加到ReadOuterXml()返回的字符串中,因为ReadOuterXml() 旨在不改变返回的XML的语义。显然,在XML中,有一个default namespace应用于<IWantThis>的某个父节点-作为默认名称空间,它递归地应用于<IWantThis>本身。要保留此名称空间成员身份,ReadOuterXml()必须在写出嵌套XML时发出默认名称空间。

    如果您确实要完全忽略XML上的名称空间,则需要创建自定义XmlReader,例如如

    所示
  2. 您需要为预期根节点为XmlSerializer的{​​{1}}构造一个SomeClass。您可以使用XmlSerializer(Type,XmlRootAttribute)构造函数来执行此操作,但是,如果这样做,您必须静态缓存并重用序列化程序,以避免严重的内存泄漏,如 {{3 }}

  3. 您正在创建要反序列化的元素的本地副本<IWantThis>,然后重新解析该本地副本。不需要这样做,您可以使用Memory Leak using StreamReader and XmlSerializer来反序列化XML的一部分。

将所有这些问题放在一起,您的wantedNodeContents可能像这样:

GetObjectFromXml()

演示小提琴XmlReader.ReadSubtree()