这是我试图解决的问题的一个虚构的例子.如果我在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文档的"部分"吗?
谢谢!-麦克风
ps示例xml从如何反序列化XML文档中被盗
这可能是一个旧的线程,但无论如何我会发布.我有同样的问题(需要从一个超过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的一部分(只是描述文件的一些细节,这可能有助于用户决定文件是否是他想要加载的).
来自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 ConcurrentDictionaryCache = 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); } }