2015-06-10 115 views
1

我有兩個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"); 
      } 
     }   
} 

我想將僅在格式2中具有Type="Print"的XML的單節點轉化爲Template類。有什麼可以反序列化XML文件(Foarmat 1和單個節點的格式2)到Template類的通用方法?

回答

0

是的,這可以通過Linq to XMLXmlSerializer結合完成的:

  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類有一個bug:你需要標記PrintWidthPrintHeight[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"); 
     } 
    } 
}