当前位置:  开发笔记 > 编程语言 > 正文

如何在C#中仅反序列化部分XML文档

如何解决《如何在C#中仅反序列化部分XML文档》经验,为你挑选了2个好方法。

这是我试图解决的问题的一个虚构的例子.如果我在C#中工作,并且像这样使用XML:



  
    1020
    Nissan
    Sentra
  
  
    1010
    Toyota
    Corolla
  
  
    Acme Sales
    
       
          1000
          Dollars
    ... and on... and on....
  

SalesPerson中的XML可能非常长,大小为兆字节.我想反序列化标记,不反序列化SalesPerson XML元素,而是保持原始形式"以后".

基本上我希望能够将其用作XML的Objects表示.

[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
    [XmlArrayItem(typeof(Car))]
    public Car[] Car { get; set; }

    public Stream SalesPerson { get; set; }
}

public class Car
{
    [System.Xml.Serialization.XmlElementAttribute("StockNumber")]
    public string StockNumber{ get; set; }

    [System.Xml.Serialization.XmlElementAttribute("Make")]
    public string Make{ get; set; }

    [System.Xml.Serialization.XmlElementAttribute("Model")]
    public string Model{ get; set; }
}

其中Cars对象上的SalesPerson属性将包含一个流,该流具有在通过XmlSerializer运行后在 xml元素内的原始xml.

可以这样做吗?我可以选择仅反序列化xml文档的"部分"吗?

谢谢!-麦克风

ps示例xml从如何反序列化XML文档中被盗



1> 小智..:

这可能是一个旧的线程,但无论如何我会发布.我有同样的问题(需要从一个超过1MB的文件反序列化10kb的数据).在主对象(具有需要反序列化的InnerObject)中,我实现了一个IXmlSerializable接口,然后更改了ReadXml方法.

我们有xmlTextReader作为输入,第一行是读取XML标记:

reader.ReadToDescendant("InnerObjectTag"); //tag which matches the InnerObject

然后为我们想要反序列化和反序列化的对象类型创建XMLSerializer

XmlSerializer   serializer = new XmlSerializer(typeof(InnerObject));

this.innerObject = serializer.Deserialize(reader.ReadSubtree()); //this gives serializer the part of XML that is for  the innerObject data

reader.close(); //now skip the rest 

这为我节省了大量反序列化的时间,并允许我只读取XML的一部分(只是描述文件的一些细节,这可能有助于用户决定文件是否是他想要加载的).



2> Stig Schmidt..:

来自user271807 的接受的答案是一个很好的解决方案,但我发现,我还需要设置片段的xml根,以避免异常,内部异常说明如下:

...xmlns=''> was not expected

当我尝试仅反序列化此xml文档的内部Authentication元素时,会抛出此异常:



                         
      xxx
      xxx                
  

所以我最终创建了这个扩展方法作为可重用的解决方案- 警告包含内存泄漏,见下文:

public static T DeserializeXml(this string @this, string innerStartTag = null)
        {
            using (var stringReader = new StringReader(@this))
            using (var xmlReader = XmlReader.Create(stringReader)) {
                if (innerStartTag != null) {
                    xmlReader.ReadToDescendant(innerStartTag);
                    var xmlSerializer = new XmlSerializer(typeof(T), new XmlRootAttribute(innerStartTag));
                    return (T)xmlSerializer.Deserialize(xmlReader.ReadSubtree());
                }
                return (T)new XmlSerializer(typeof(T)).Deserialize(xmlReader);
            }
        }

更新2017年3月20日:正如下面的评论所指出的,使用XmlSerializer的一个构造函数时存在内存泄漏问题,所以我最终使用了一个缓存解决方案,如下所示:

    /// 
    ///     Deserialize XML string, optionally only an inner fragment of the XML, as specified by the innerStartTag parameter.
    /// 
    public static T DeserializeXml(this string @this, string innerStartTag = null) {
        using (var stringReader = new StringReader(@this)) {
            using (var xmlReader = XmlReader.Create(stringReader)) {
                if (innerStartTag != null) {
                    xmlReader.ReadToDescendant(innerStartTag);
                    var xmlSerializer = CachingXmlSerializerFactory.Create(typeof (T), new XmlRootAttribute(innerStartTag));
                    return (T) xmlSerializer.Deserialize(xmlReader.ReadSubtree());
                }
                return (T) CachingXmlSerializerFactory.Create(typeof (T), new XmlRootAttribute("AutochartistAPI")).Deserialize(xmlReader);
            }
        }
    }
/// 
///     A caching factory to avoid memory leaks in the XmlSerializer class.
/// See http://dotnetcodebox.blogspot.dk/2013/01/xmlserializer-class-may-result-in.html
/// 
public static class CachingXmlSerializerFactory {
    private static readonly ConcurrentDictionary Cache = new ConcurrentDictionary();
    public static XmlSerializer Create(Type type, XmlRootAttribute root) {
        if (type == null) {
            throw new ArgumentNullException(nameof(type));
        }
        if (root == null) {
            throw new ArgumentNullException(nameof(root));
        }
        var key = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", type, root.ElementName);
        return Cache.GetOrAdd(key, _ => new XmlSerializer(type, root));
    }
    public static XmlSerializer Create(XmlRootAttribute root) {
        return Create(typeof (T), root);
    }
    public static XmlSerializer Create() {
        return Create(typeof (T));
    }
    public static XmlSerializer Create(string defaultNamespace) {
        return Create(typeof (T), defaultNamespace);
    }
    public static XmlSerializer Create(Type type) {
        return new XmlSerializer(type);
    }
    public static XmlSerializer Create(Type type, string defaultNamespace) {
        return new XmlSerializer(type, defaultNamespace);
    }
}

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有