2015-06-10 86 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"); 
     } 
    } 
}