按属性值获取xml节点并对该节点进行反序列化
本文关键字:节点 反序列化 获取 xml 属性 | 更新日期: 2023-09-27 17:54:42
我有两个XML文件,如下所示
格式1:
<Template Type="Print">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>
格式2:
<Templates>
<Template Type="Print">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>
<Template Type="Print">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>
</Templates>
我已经为Format 1创建了如下的映射类:
public class Template
{
private double _printWidth;
private double _printHeight;
/// <summary>
/// Print width in inches
/// </summary>
[System.Xml.Serialization.XmlAttributeAttribute()]
public double PrintWidth {
get {
return this._printWidth;
}
set {
this._printWidth = value;
this.RaisePropertyChanged("PrintWidth");
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
public double PrintHeight {
get {
return this._printHeight;
}
set {
this._printHeight = value;
this.RaisePropertyChanged("PrintHeight");
}
}
}
我想在格式2中只设计一个XML节点,该节点将Type="Print"
放入Template
类。是否有任何通用的方法,我可以反序列化两个XML文件(格式1和格式2的单个节点)到Template
类?
是的,这可以通过结合Linq to XML与XmlSerializer
:
-
加载XML到
XDocument
-
使用linq在XML元素层次结构中查找具有相应属性的合适元素
-
反序列化选定的元素,使用
XElement.CreateReader()
传递一个XmlReader
来读取该元素及其后代。
例如:
public static void Test()
{
string xml1 = @"<Template Type=""Print"">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>";
string xml2 = @"<Templates>
<Template Type=""Print"">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>
<Template Type=""Print"">
<PrintWidth>7</PrintWidth>
<PrintHeight>5</PrintHeight>
</Template>
</Templates>";
var template1 = ExtractTemplate(xml1);
var template2 = ExtractTemplate(xml2);
Debug.Assert(template1 != null && template2 != null
&& template1.PrintWidth == template2.PrintWidth
&& template1.PrintWidth == 7
&& template1.PrintHeight == template2.PrintHeight
&& template1.PrintHeight == 5); // No assert
}
public static Template ExtractTemplate(string xml)
{
// Load the XML into an XDocument
var doc = XDocument.Parse(xml);
// Find the first element named "Template" with attribute "Type" that has value "Print".
var element = doc.Descendants("Template").Where(e => e.Attributes("Type").Any(a => a.Value == "Print")).FirstOrDefault();
// Deserialize it to the Template class
var template = (element == null ? null : element.Deserialize<Template>());
return template;
}
使用扩展方法:
public static class XObjectExtensions
{
public static T Deserialize<T>(this XContainer element)
{
return element.Deserialize<T>(new XmlSerializer(typeof(T)));
}
public static T Deserialize<T>(this XContainer element, XmlSerializer serializer)
{
using (var reader = element.CreateReader())
{
object result = serializer.Deserialize(reader);
if (result is T)
return (T)result;
}
return default(T);
}
}
顺便说一句,您的Template
类有一个错误:您需要用[XmlElement]
而不是[XmlAttribute]
标记PrintWidth
和PrintHeight
来正确地反序列化该XML:
public class Template
{
private double _printWidth;
private double _printHeight;
/// <summary>
/// Print width in inches
/// </summary>
[System.Xml.Serialization.XmlElementAttribute()]
public double PrintWidth
{
get
{
return this._printWidth;
}
set
{
this._printWidth = value;
this.RaisePropertyChanged("PrintWidth");
}
}
[System.Xml.Serialization.XmlElementAttribute()]
public double PrintHeight
{
get
{
return this._printHeight;
}
set
{
this._printHeight = value;
this.RaisePropertyChanged("PrintHeight");
}
}
}