C# 将xml反序列化为具有不同层次结构的类?
这将把xml样本反序列化到“XmlModel”类中 我使用的是遗留代码,除了更改XmlAttributes之外,我无法更改XmlModel类。问题是:实际的Xml没有“foo”节点:C# 将xml反序列化为具有不同层次结构的类?,c#,xml,xmlserializer,C#,Xml,Xmlserializer,这将把xml样本反序列化到“XmlModel”类中 我使用的是遗留代码,除了更改XmlAttributes之外,我无法更改XmlModel类。问题是:实际的Xml没有“foo”节点: stringxml=@” 1. 2. "; 所以现在我不得不让反序列化程序吞下这个xml和输出类型XmlModel。如果没有Xslt预处理或其他更复杂的方法,这是可能的吗?如果您愿意使用另一种反序列化方法,这将起作用。它应该与XmlSerializer一样快(如果不是更快的话)。它只需在原始xml上打开一个Xml
stringxml=@”
1.
2.
";
所以现在我不得不让反序列化程序吞下这个xml和输出类型XmlModel。如果没有Xslt预处理或其他更复杂的方法,这是可能的吗?如果您愿意使用另一种反序列化方法,这将起作用。它应该与
XmlSerializer
一样快(如果不是更快的话)。它只需在原始xml上打开一个XmlReader
,移动到第一个“数据”元素,将数据转储到列表中,然后填充并从中返回XmlModel
LINQPad文件可用
公共XmlModel GetXmlModel()
{
字符串xml=@“
1.
2.
";
使用(var reader=XmlReader.Create(newstringreader(xml)))
{
reader.MoveToContent();
var data=新列表();
while(reader.Read())
{
if(reader.NodeType==XmlNodeType.Element)
{
var element=XNode.ReadFrom(reader)作为XElement;
开关(element.Name.LocalName)
{
案例“酒吧”:
{
数据。添加(元素。值);
打破
}
}
}
}
返回新的XmlModel(){Foo=data};
}
}
如果bar
类不仅仅是一个简单的内在类型,例如string
,那么这显然会变得更复杂,您可以使用它为XmlModel
指定备用XML属性,然后通过执行以下操作来使用这些属性:
var serializer = new XmlSerializer(typeof(XmlModel), overrides).
但是,请注意来自的以下警告:
为了提高性能,XML序列化基础结构动态生成程序集以序列化和反序列化指定类型。基础结构查找并重用这些程序集。此行为仅在使用以下构造函数时发生:
XmlSerializer.XmlSerializer(类型)
XmlSerializer.XmlSerializer(类型, (字符串)
如果使用任何其他构造函数,将生成同一程序集的多个版本,并且从未卸载,这将导致内存泄漏和性能低下。最简单的解决方案是使用前面提到的两个构造函数之一。否则,必须将程序集缓存在哈希表中
以下静态类创建并缓存2个序列化程序,一个用于XmlModel
的“当前”版本,另一个用于
元素缺少外部容器元素的“备用”版本:
public static class XmlModelSerializer<TRoot>
{
static XmlSerializer alternateSerializerInstance;
static XmlSerializer currentSerializerInstance;
public static XmlSerializer AlternateSerializerInstance { get { return alternateSerializerInstance; } }
public static XmlSerializer CurrentSerializerInstance { get { return currentSerializerInstance; } }
static XmlModelSerializer()
{
XmlAttributes alternateAttributes = new XmlAttributes
{
XmlElements = { new XmlElementAttribute("bar") },
};
XmlAttributeOverrides alternateOverrides = new XmlAttributeOverrides();
alternateOverrides.Add(typeof(XmlModel), "Foo", alternateAttributes);
alternateSerializerInstance = new XmlSerializer(typeof(TRoot), alternateOverrides);
XmlAttributes currentAttributes = new XmlAttributes
{
XmlArray = new XmlArrayAttribute("foo"),
XmlArrayItems = { new XmlArrayItemAttribute("bar") },
};
XmlAttributeOverrides currentOverrides = new XmlAttributeOverrides();
currentOverrides.Add(typeof(XmlModel), "Foo", currentAttributes);
currentSerializerInstance = new XmlSerializer(typeof(TRoot), currentOverrides);
}
}
您只需执行以下操作:
var dS = XmlModelSerializer<XmlModel>.AlternateSerializerInstance;
using (var reader = new StringReader(xml))
{
return (XmlModel) dS.Deserialize(reader);
}
var dS=XmlModelSerializer.AlternateSerializerInstance;
使用(var reader=newstringreader(xml))
{
返回(XmlModel)dS.反序列化(读取器);
}
显示两种格式的反序列化的示例。您可以反序列化为与XML匹配的格式,然后使用类似于“升级”的内容。不是超级性能,但我不知道你在这方面的要求是什么,这可能是可以接受的。你还有什么其他限制?您可以使用不同的反序列化方法吗?@Bradley Uffner使用代理类+自动映射是一种选择,但我认为这需要付出一些努力+性能损失(比XSLT prrprocessor更重要)。另一种序列化程序是我没有考虑过的选项,如果仅仅是XmlAttribute技巧不起作用(我希望它们会起作用),它可能是一种解决方案。使用
XmlSerializer
和Attributes
可能有一些内置的方法来实现这一点。这是.NET的一个领域,我还没有深入研究过,所以我不确定。我只是想找到适合您的选项。遗留代码可能是一成不变的,但Xml肯定不是。您是否考虑过在尝试反序列化之前临时修改Xml(添加Foo根节点)?否则,在我看来,您将需要一个自定义反序列化程序。您的答案看起来好像是从中改编的,但不幸的是,MSDN代码有一个bug——它在XML未缩进时跳过元素。有关分析,请参阅。就我个人而言,我建议只加载到XElement
中,并在内存中执行所有操作,正是因为直接使用XmlReader
非常繁琐。我承认,我曾浏览过该示例以供参考。您的建议也是我的首选方式,但我一直在努力使事情尽可能快,因为op在讨论中提到了性能。这不仅表明在公共列表Foo{get;set;}上面使用[XmlElement(“bar”)]将省略“Foo”节点,它还展示了如何在两个反序列化(grand)之间动态切换。
public XmlModel GetXmlModel()
{
string xml = @"<?xml version=""1.0"" encoding=""utf-16""?>
<root>
<bar>1</bar>
<bar>2</bar>
</root>";
using (var reader = XmlReader.Create(new StringReader(xml)))
{
reader.MoveToContent();
var data = new List<string>();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
var element = XNode.ReadFrom(reader) as XElement;
switch (element.Name.LocalName)
{
case "bar":
{
data.Add(element.Value);
break;
}
}
}
}
return new XmlModel() { Foo = data };
}
}
var serializer = new XmlSerializer(typeof(XmlModel), overrides).
public static class XmlModelSerializer<TRoot>
{
static XmlSerializer alternateSerializerInstance;
static XmlSerializer currentSerializerInstance;
public static XmlSerializer AlternateSerializerInstance { get { return alternateSerializerInstance; } }
public static XmlSerializer CurrentSerializerInstance { get { return currentSerializerInstance; } }
static XmlModelSerializer()
{
XmlAttributes alternateAttributes = new XmlAttributes
{
XmlElements = { new XmlElementAttribute("bar") },
};
XmlAttributeOverrides alternateOverrides = new XmlAttributeOverrides();
alternateOverrides.Add(typeof(XmlModel), "Foo", alternateAttributes);
alternateSerializerInstance = new XmlSerializer(typeof(TRoot), alternateOverrides);
XmlAttributes currentAttributes = new XmlAttributes
{
XmlArray = new XmlArrayAttribute("foo"),
XmlArrayItems = { new XmlArrayItemAttribute("bar") },
};
XmlAttributeOverrides currentOverrides = new XmlAttributeOverrides();
currentOverrides.Add(typeof(XmlModel), "Foo", currentAttributes);
currentSerializerInstance = new XmlSerializer(typeof(TRoot), currentOverrides);
}
}
<root>
<bar>1</bar>
<bar>2</bar>
</root>
var dS = XmlModelSerializer<XmlModel>.AlternateSerializerInstance;
using (var reader = new StringReader(xml))
{
return (XmlModel) dS.Deserialize(reader);
}