按属性值获取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类?

按属性值获取xml节点并对该节点进行反序列化

是的,这可以通过结合Linq to XML与XmlSerializer:

  1. 加载XML到XDocument

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

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