Получить узел XML по значению атрибута и десериализовать этот узел
У меня есть два файла 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, как показано ниже:
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");
}
}
}
Я хотел бы выделить только один узел XML в формате 2, который имеет Type="Print"
в Template
учебный класс. Есть ли какой-либо общий способ, с помощью которого я могу десериализовать оба XML-файла (Foarmat 1 и один узел формата 2) в Template
учебный класс?
1 ответ
Да, это можно сделать путем объединения Linq в 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
класс имеет ошибку: нужно пометить PrintWidth
а также PrintHeight
с [XmlElement]
скорее, чем [XmlAttribute]
чтобы правильно десериализовать этот 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");
}
}
}