2012-11-16 53 views
1

我有一個XML源文檔,在根節點下有多個「report」節點。我需要將每個「報告」節點讀入它自己的DataTable。它看起來像我要麼需要使用XSL樣式表來獲得它那將很好地工作或遍歷我的XML元素,像這樣的格式轉換我的源XML數據:將多個xml表(位於同一個根節點下)讀入DataTables/DataSet中

namespace XmlParse2 
{ 
    class Program 
    { 
     static IEnumerable<string> expectedFields = new List<string>() { "Field1", "Field2", "Field3", "Field4" }; 

     static void Main(string[] args) 
     { 
      string xml = @"<Root> 
          <Report1> 
           <Row> 
           <Field1>data1-1</Field1> 
           <Field2>data1-2</Field2> 
           <Field4>data1-4</Field4> 
           </Row> 
           <Row> 
           <Field1>data2-1</Field1> 
           <Field2>data2-2</Field2> 
           </Row> 
          </Report1> 
          <Report2> 
           <Row> 
           <Field1>data1-1</Field1> 
           <Field4>data1-4</Field4> 
           </Row> 
           <Row> 
           <Field1>data2-1</Field1> 
           <Field3>data2-3</Field3> 
           </Row> 
          </Report2> 
          </Root>"; 

      DataTable report1 = new DataTable("Report1"); 
      report1.Columns.Add("Field1"); 
      report1.Columns.Add("Field2"); 
      report1.Columns.Add("Field3"); 
      report1.Columns.Add("Field4"); 

      DataTable report2 = new DataTable("Report2"); 
      report2.Columns.Add("Field1"); 
      report2.Columns.Add("Field2"); 
      report2.Columns.Add("Field3"); 
      report2.Columns.Add("Field4"); 

      var doc = XDocument.Parse(xml); 
      var report1Data = doc.Root.Elements("Report1").Elements("Row").Select(record => MapRecord(record)); 
      var report2Data = doc.Root.Elements("Report2").Elements("Row").Select(record => MapRecord(record)); 

      report1 = addRows(report1, report1Data); 
      report2 = addRows(report2, report2Data); 

      Console.ReadLine(); 
     } 

     public static Dictionary<string, string> MapRecord(XElement element) 
     { 
      var output = new Dictionary<string, string>(); 
      foreach (var field in expectedFields) 
      { 
       bool hasField = element.Elements(field).Any(); 
       if (hasField) 
       { 
        output.Add(field, element.Elements(field).First().Value); 
       } 
      } 
      return output; 
     } 

     public static DataTable addRows(DataTable table, IEnumerable<Dictionary<string, string>> data) 
     { 
      foreach (Dictionary<string, string> dict in data) 
      { 
       DataRow row = table.NewRow(); 

       foreach(var item in dict) 
       { 
        row[item.Key] = item.Value; 
       } 

       table.Rows.Add(row); 
      } 

      return table; 
     } 
    } 
} 

與我的源的問題數據不工作似乎是Report1和Report2都具有名爲「行」的子節點,我嘗試使用DataSet.ReadXml做東西不成功,因爲我的代碼只將名爲Row的所有節點組合到一個DataTable中而不是單獨的DataTable中。 :/

我錯過了什麼?

回答

1
XDocument xdoc = XDocument.Load(path_to_xml); 
var tables = xdoc.Root.Elements() 
       .Select(report => { 
        DataTable table = new DataTable(report.Name.LocalName); 
        var fields = report 
          .Descendants("Row") 
          .SelectMany(row => row.Elements() 
                .Select(e => e.Name.LocalName)) 
          .Distinct(); 

        foreach(string field in fields) 
         table.Columns.Add(field); 

        foreach(var row in report.Descendants("Row")) 
        { 
         DataRow dr = table.NewRow(); 
         foreach(var field in row.Elements()) 
          dr[field.Name.LocalName] = (string)field; 
         table.Rows.Add(dr); 
        }         

        return table; 
       }); 

此查詢將返回IEnumerable<DataTable>。每個數據表只包含那些在xml中有值的列。從xml檢索的列名稱可能對於每個表不同。爲了您的樣本結構看起來是這樣的:

DataTable: Report1 
    Columns: Field1, Field2, Field4 

DataTable: Report2 
    Columns: Field1, Field3, Field4 

所有行的數據將被添加到每個表。


你可以提取一些代碼給方法。這將使得代碼更容易理解:

XDocument xdoc = XDocument.Load(path_to_xml); 
var tables = xdoc.Root.Elements() 
       .Select(report => CreateTableFrom(report)); 

和方法:

private static DataTable CreateTableFrom(XElement report) 
{ 
    DataTable table = new DataTable(report.Name.LocalName); 
    table.Columns.AddRange(GetColumnsOf(report)); 

    foreach (var row in report.Descendants("Row")) 
    { 
     DataRow dr = table.NewRow(); 
     foreach (var field in row.Elements()) 
      dr[field.Name.LocalName] = (string)field; 
     table.Rows.Add(dr); 
    } 

    return table; 
} 

private static DataColumn[] GetColumnsOf(XElement report) 
{ 
    return report.Descendants("Row") 
       .SelectMany(row => row.Elements().Select(e => e.Name.LocalName)) 
       .Distinct() 
       .Select(field => new DataColumn(field)) 
       .ToArray(); 
} 
+0

謝謝!我真的需要學習Linq。 – programmer

相關問題