通过属性值获取 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:

来完成
  1. 将 XML 加载到 XDocument

  2. 使用 linq 在 XML 元素层次结构中查找具有适当属性的适当元素。

  3. 反序列化所选元素,使用 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] 标记 PrintWidthPrintHeight正确反序列化 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");
        }
    }
}