Могу ли я «сплющить» XDocument с помощью Linq? - PullRequest
1 голос
/ 17 января 2012

У меня есть сильно вложенный XML-документ, который мне нужно загрузить в базу данных для дополнительной обработки.По разным причинам, выходящим за рамки этого обсуждения, мне нужно «сплющить» эту структуру, затем загрузить ее в DataTables, а затем я могу SQLBulkCopy ее в базу данных, где она будет обрабатываться.Итак, предположим, что мой оригинальный XML выглядит примерно так (мой еще более сильно вложен, но это основная идея):

<data>
    <report id="1234" name="XYZ">
        <department id="234" name="Accounting">
            <item id="ABCD" name="some item">
                <detail id="detail1" value="1"/>                    
                <detail id="detail2" value="2"/>                    
                <detail id="detail3" value="3"/>                    
            </item>
        </department>      
    </report>
 </data>   

, и я хочу свести это в одну (хотя и избыточную) структуру таблицыгде каждый атрибут становится столбцом (т. е. ReportId, ReportName, DepartmentId, DepartmentName, ItemId, ItemName, Detail1, Detail2, Detail3).

Так что мой вопрос просто: «Можно ли сделать это простым запросом Linq»?Раньше я просто писал несколько XSLT и покончил с этим, но мне любопытно, может ли библиотека Linq выполнить то же самое?

спасибо!

1 Ответ

3 голосов
/ 17 января 2012

Это то, что вы ищете?

var doc = XDocument.Load(fileName);
var details =
    from report in doc.Root.Elements("report")
    from department in report.Elements("department")
    from item in department.Elements("item")
    from detail in item.Elements("detail")
    select new
    {
        ReportId = (int)report.Attribute("id"),
        ReportName = (string)report.Attribute("name"),
        DepartmentId = (int)department.Attribute("id"),
        DepartmentName = (string)department.Attribute("name"),
        ItemId = (string)item.Attribute("id"),
        ItemName = (string)item.Attribute("name"),
        DetailId = (string)detail.Attribute("id"),
        DetailValue = (int)detail.Attribute("value"),
    };

Если вы хотите использовать его как DataTable, вы можете использовать следующий метод расширения:

public static DataTable ToDataTable<T>(this IEnumerable<T> source)
{
    PropertyInfo[] properties = typeof(T).GetProperties()
                                         .Where(p => p.CanRead && !p.GetIndexParameters().Any())
                                         .ToArray();

    DataTable table = new DataTable();
    foreach (var p in properties)
    {
        Type type = p.PropertyType;
        bool allowNull = !type.IsValueType;
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            allowNull = true;
            type = Nullable.GetUnderlyingType(type);
        }
        DataColumn column = table.Columns.Add(p.Name, type);
        column.AllowDBNull = allowNull;
        column.ReadOnly = !p.CanWrite;
    }

    foreach (var item in source)
    {
        DataRow row = table.NewRow();
        foreach (var p in properties)
        {
            object value = p.GetValue(item, null) ?? DBNull.Value;
            row[p.Name] = value;
        }
        table.Rows.Add(row);
    }

    return table;
}

Используйте это так:

var table = details.CopyToDataTable();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...