1

ルートノードの下に複数の「レポート」ノードがあるXMLソースドキュメントがあります。各「レポート」ノードを独自のDataTableに読み込む必要があります。xslスタイルシートを使用してソースXMLデータを変換し、適切に機能する形式にするか、次のようにxml要素を反復処理する必要があるようです。

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の両方に「Row」という名前の子ノードがあり、コードがRowという名前のすべてのノードを1つのDataTableにグループ化するだけなので、DataSet.ReadXmlを使用して何かを実行しようとしても成功しないことです。個別のDataTableの代わりに。:/

私は何が欠けていますか?

4

1 に答える 1

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();
}
于 2012-11-16T08:58:56.973 に答える