2015-05-07 21 views
0

我正在實現一個Windows服務,我需要使用REST的WebService,我想解析這個列表,但我不知道如何。 我的問題是,這些字段的名稱與數據是分開的。需要解析XML到列表<Object>,名稱字段與數據分離

結構我得到的是這樣的:

<?xml version="1.0" encoding="utf-8" ?> 
<xml> 
    <result>OK</result> 
<headers> 
    <header>lastname</header> 
    <header>firstname</header> 
    <header>Age</header> 
    </headers> 
<data> 
<datum> 
    <item>Kelly</item> 
    <item>Grace</item> 
    <item>33</item> 
</datum> 
    </data> 
</xml> 
+0

這是實際結構嗎?看起來更像是一個具有一堆屬性的單個對象。我建議讓一個類型化的XmlSerializer來處理這個,而不是自己解析它,但爲了給出一個有效的答案,我需要看到真實的結構。 – Filburt

+0

結構是真實的(有更多的領域),但它是。我想創建一個只有標題名稱的對象列表,但正如你所說,最好的方法是使用XmlSerializer併爲我自己解析。 – Baladier

+0

如果你只對'header'元素感興趣,你可以指定'headers'作爲你的反序列化類型的根,並且不用麻煩自己來處理結構的其餘部分。 dbc的答案應該給你一個出發點。 – Filburt

回答

1

您可以使用XmlSerializer反序列化XML到反映其結構的C#類。例如:

[XmlRoot("xml")] // Indicates that the root element is named "xml" 
public class XmlResponse 
{ 
    [XmlElement("result")] // Indicates that this element is named "result" 
    public string Result { get; set; } 

    [XmlArray("headers")] // Indicates two-level list with outer element named "headers" and inner elements named "header" 
    [XmlArrayItem("header")] 
    public List<string> Headers { get; set; } 

    [XmlArray("data")] // Indicates two-level list with outer element named "data" and inner elements named "datum" 
    [XmlArrayItem("datum")] 
    public List<XmlResponseDatum> Data { get; set; } 
} 

public class XmlResponseDatum 
{ 
    [XmlElement("item")] // Indicates a one-level list with repeated elements named "item". 
    public List<string> Items { get; set; } 
} 

,你可以反序列化,如:

public static T LoadFromXML<T>(string xmlString) 
    { 
     using (StringReader reader = new StringReader(xmlString)) 
     { 
      object result = new XmlSerializer(typeof(T)).Deserialize(reader); 
      if (result is T) 
      { 
       return (T)result; 
      } 
     } 
     return default(T); 
    } 

    public static string GetXml<T>(T obj) 
    { 
     using (var textWriter = new StringWriter()) 
     { 
      var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " }; // For cosmetic purposes. 
      using (var xmlWriter = XmlWriter.Create(textWriter, settings)) 
       new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj); 
      return textWriter.ToString(); 
     } 
    } 

    public static void Test() 
    { 
     string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?> 
      <xml> 
       <result>OK</result> 
      <headers> 
       <header>lastname</header> 
       <header>firstname</header> 
       <header>Age</header> 
       </headers> 
      <data> 
      <datum> 
       <item>Kelly</item> 
       <item>Grace</item> 
       <item>33</item> 
      </datum> 
       </data> 
      </xml>"; 
     var response = LoadFromXML<XmlResponse>(xml); 
     Debug.WriteLine(GetXml(response)); 
0

作爲替代,這裏是不需要是XML裝飾一些的XDocument和使用對象。

我提倡這種方法,因爲在Xml結構改變的情況下,更容易調整XDocument/Xpath語句.....與XmlAttributes相反。

這也允許使用相同的對象,即使有不同的xml流水化它。您只需爲每個Xml輸入寫一個不同的XDocument「碎紙機」。

[DebuggerDisplay("MyNotUsedStringKey = {MyNotUsedStringKey}")] 
public class ImportParent 
{ 
    public ImportParent() 
    { 
     this.MyNotUsedStringKey = Guid.NewGuid().ToString("N"); 
     this.ImportChildren = new ImportChildCollection(); 
    } 

    public ImportChildCollection ImportChildren { get; set; } 
    public string MyNotUsedStringKey { get; set; } 

} 

public class ImportChildCollection : List<ImportChild> 
{ 
    public ImportChildCollection() { } 
    public ImportChildCollection(IEnumerable<ImportChild> src) 
    { 
     if (null != src) 
     { 
      foreach (ImportChild item in src) 
      { 
       item.Ordinal = this.Count + 1; 
       base.Add(item); 
      } 
     } 

     //AddRange(src); 
    } 
} 

[DebuggerDisplay("MyStringKey = {MyStringKey}, MyStringValue='{MyStringValue}', Ordinal='{Ordinal}'")] 
public class ImportChild 
{ 
    public ImportChild() 
    { 
    } 

    public int Ordinal { get; set; } 
    public string MyStringKey { get; set; } 
    public string MyStringValue { get; set; } 
} 




      string xmlString = @"<?xml version=""1.0"" encoding=""utf-8"" ?> 
      <xml> 
       <result>OK</result> 
       <headers> 
        <header>lastname</header> 
        <header>firstname</header> 
        <header>Age</header> 
       </headers> 
       <data> 
        <datum> 
         <item>Kelly</item> 
         <item>Grace</item> 
         <item>33</item> 
        </datum> 
       </data> 
      </xml>   "; 

      XDocument xDoc = XDocument.Parse(xmlString); 

      //XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003"); 
      string ns = string.Empty; 




      List<ImportParent> parentKeys = new List<ImportParent> 
      (
       from list in xDoc.Descendants(ns + "xml") 
       from item1 in list.Elements(ns + "headers") 
       where item1 != null 
       select new ImportParent 
       { 
        //note that the cast is simpler to write than the null check in your code 
        //http://msdn.microsoft.com/en-us/library/bb387049.aspx 
        ImportChildren = new ImportChildCollection 
        (
         from detail in item1.Descendants("header") 
         select new ImportChild 
         { 
          MyStringKey = detail == null ? string.Empty : detail.Value 
         } 
        ) 
       } 
      ); 


      List<ImportParent> parentValues = new List<ImportParent> 
      (
       from list in xDoc.Descendants(ns + "xml") 
       from item1 in list.Elements(ns + "data") 
       from item2 in item1.Elements(ns + "datum") 
       where item1 != null && item2 != null 
       select new ImportParent 
       { 
        //note that the cast is simpler to write than the null check in your code 
        //http://msdn.microsoft.com/en-us/library/bb387049.aspx 
        ImportChildren = new ImportChildCollection 
         (
          from detail in item1.Descendants("item") 
          select new ImportChild 
          { 
           MyStringValue = detail == null ? string.Empty : detail.Value 
          } 
         ) 
       } 
      ); 

      /*Match up the Keys to the Values using "Ordinal" matches*/ 
      foreach (ImportParent parent in parentKeys) 
      { 
       foreach (ImportChild child in parent.ImportChildren) 
       { 
        ImportChild foundMatch = parentValues.SelectMany(x => x.ImportChildren).Where(c => c.Ordinal == child.Ordinal).FirstOrDefault(); 
        if (null != foundMatch) 
        { 
         child.MyStringValue = foundMatch.MyStringValue; 
        } 
       } 
      } 

      foreach (ImportParent parent in parentKeys) 
      { 
       foreach (ImportChild child in parent.ImportChildren) 
       { 
        Console.WriteLine("Key={0}, Value={1}", child.MyStringKey, child.MyStringValue); 
       } 
      }