Mik*_*ike 27 c# xml serialization xml-serialization
这是我试图解决的问题的一个虚构的例子.如果我在C#中工作,并且像这样使用XML:
<?xml version="1.0" encoding="utf-8"?>
<Cars>
<Car>
<StockNumber>1020</StockNumber>
<Make>Nissan</Make>
<Model>Sentra</Model>
</Car>
<Car>
<StockNumber>1010</StockNumber>
<Make>Toyota</Make>
<Model>Corolla</Model>
</Car>
<SalesPerson>
<Company>Acme Sales</Company>
<Position>
<Salary>
<Amount>1000</Amount>
<Unit>Dollars</Unit>
... and on... and on....
</SalesPerson>
</Cars>
Run Code Online (Sandbox Code Playgroud)
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; }
}
Run Code Online (Sandbox Code Playgroud)
其中Cars对象上的SalesPerson属性将包含一个流,该流具有在通过XmlSerializer运行后在<SalesPerson> xml元素内的原始xml.
可以这样做吗?我可以选择仅反序列化xml文档的"部分"吗?
谢谢!-麦克风
ps示例xml从如何反序列化XML文档中被盗
小智 39
这可能是一个旧的线程,但无论如何我会发布.我有同样的问题(需要从一个超过1MB的文件反序列化10kb的数据).在主对象(具有需要反序列化的InnerObject)中,我实现了一个IXmlSerializable接口,然后更改了ReadXml方法.
我们有xmlTextReader作为输入,第一行是读取XML标记:
reader.ReadToDescendant("InnerObjectTag"); //tag which matches the InnerObject
Run Code Online (Sandbox Code Playgroud)
然后为我们想要反序列化和反序列化的对象类型创建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
Run Code Online (Sandbox Code Playgroud)
这为我节省了大量反序列化的时间,并允许我只读取XML的一部分(只是描述文件的一些细节,这可能有助于用户决定文件是否是他想要加载的).
来自user271807 的接受的答案是一个很好的解决方案,但我发现,我还需要设置片段的xml根,以避免异常,内部异常说明如下:
...xmlns=''> was not expected
Run Code Online (Sandbox Code Playgroud)
当我尝试仅反序列化此xml文档的内部Authentication元素时,会抛出此异常:
<?xml version=""1.0"" encoding=""UTF-8""?>
<Api>
<Authentication>
<sessionid>xxx</sessionid>
<errormessage>xxx</errormessage>
</Authentication>
</ApI>
Run Code Online (Sandbox Code Playgroud)
所以我最终创建了这个扩展方法作为可重用的解决方案- 警告包含内存泄漏,见下文:
public static T DeserializeXml<T>(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);
}
}
Run Code Online (Sandbox Code Playgroud)
更新2017年3月20日:正如下面的评论所指出的,使用XmlSerializer的一个构造函数时存在内存泄漏问题,所以我最终使用了一个缓存解决方案,如下所示:
/// <summary>
/// Deserialize XML string, optionally only an inner fragment of the XML, as specified by the innerStartTag parameter.
/// </summary>
public static T DeserializeXml<T>(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);
}
}
}
/// <summary>
/// A caching factory to avoid memory leaks in the XmlSerializer class.
/// See http://dotnetcodebox.blogspot.dk/2013/01/xmlserializer-class-may-result-in.html
/// </summary>
public static class CachingXmlSerializerFactory {
private static readonly ConcurrentDictionary<string, XmlSerializer> Cache = new ConcurrentDictionary<string, XmlSerializer>();
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<T>(XmlRootAttribute root) {
return Create(typeof (T), root);
}
public static XmlSerializer Create<T>() {
return Create(typeof (T));
}
public static XmlSerializer Create<T>(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);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
38133 次 |
最近记录: |