通过属性值获取 xml 节点并反序列化该节点
Get xml node by attribute value and de-serialize that node
我有两个 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>
我已经为格式 1 创建了映射 Class,如下所示:
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
class。有什么通用的方法可以将 XML 文件(Foarmat 1 和格式 2 的单个节点)反序列化为 Template
class?
是的,这可以通过组合 Linq to XML with XmlSerializer
:
来完成
将 XML 加载到 XDocument
使用 linq 在 XML 元素层次结构中查找具有适当属性的适当元素。
反序列化所选元素,使用 XElement.CreateReader()
to pass an 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
class 有一个错误:你需要用 [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");
}
}
}
我有两个 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>
我已经为格式 1 创建了映射 Class,如下所示:
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
class。有什么通用的方法可以将 XML 文件(Foarmat 1 和格式 2 的单个节点)反序列化为 Template
class?
是的,这可以通过组合 Linq to XML with XmlSerializer
:
将 XML 加载到
XDocument
使用 linq 在 XML 元素层次结构中查找具有适当属性的适当元素。
反序列化所选元素,使用
XElement.CreateReader()
to pass anXmlReader
将元素及其后代读取到序列化程序。
因此,例如:
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
class 有一个错误:你需要用 [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");
}
}
}