Преобразование XML в таблицу SQL Server с помощью C# (или любого другого метода)



У меня есть около 10 000 XML-файлов, где мне нужно преобразовать их в таблицу SQL.



Однако, вот проблемы, каждый XML-файл имеет некоторые вариации между собой, поэтому для меня почти невозможно указать имя элемента. Например:



//XML #1
<color>Blue</color>
<height>14.5</height>
<weight>150</weight>
<price>56.78</price>

//XML #2
<color>Red</color>
<distance>98.7</distance>
<height>15.5</height>
<price>56.78</price>

//XML #3: Some of the elements have no value
<color />
<height>14.5</height>
<price>78.11</price>

//XML #4: Elements has parent/child
<color>
<bodyColor>Blue</bodyColor>
<frontColor>Yellow</frontColor>
<backColor>White</backColor>
</color>
<height>14.5</height>
<weight>150</weight>
<price>56.78</price>


В приведенном выше примере я должен ожидать таблицу, созданную с именем columns: color, height, weight, price, distance (поскольку XML #2 имеет расстояние), bodyColor, frontColor, backColor.



Ожидаемый результат:



XML#    color    height    weight    price    distance    bodyColor    frontColor    backColor
1 Blue 14.5 150 56.78 NULL NULL NULL NULL
2 Red 15.5 NULL 56.78 98.7 NULL NULL NULL
3 NULL 14.5 NULL 78.11 NULL NULL NULL NULL
4 NULL 14.5 150 56.78 NULL Blue Yellow White


В этом случае NULL или пустое значение являются допустимый.



Это всего лишь примеры, в каждом XML-файле содержится не менее 500 элементов. Кроме того, хотя я упомянул здесь C#, если кто-нибудь может предложить лучший способ сделать это, пожалуйста, дайте мне знать.

545   2  

2 ответов:

Одна возможность перебирать все xml-файлы и получать все уникальные теги может использовать LINQ2XML, класс HashSet и может выглядеть следующим образом:

try
{
    // add as many elements you want, they will appear only once!
    HashSet<String> uniqueTags = new HashSet<String>();
    // recursive helper delegate
    Action<XElement> addSubElements = null;
    addSubElements = (xmlElement) =>
    {
        // add the element name and 
        uniqueTags.Add(xmlElement.Name.ToString());
        // if the given element has some subelements
        foreach (var element in xmlElement.Elements())
        {
            // add them too
            addSubElements(element);
        }
    };

    // load all xml files
    var xmls = Directory.GetFiles("d:\\temp\\xml\\", "*.xml");
    foreach (var xml in xmls)
    {
        var xmlDocument = XDocument.Load(xml);
        // and take their tags
        addSubElements(xmlDocument.Root);
    }
    // list tags
    foreach (var tag in uniqueTags)
    {
        Console.WriteLine(tag);
    }
}
catch (Exception exception)
{
    Console.WriteLine(exception.Message);
}
Теперь у вас есть столбцы для основной таблицы SQL . С небольшим улучшением можно также отметить Родительский и подузлы. Это может помочь вам для нормализации.

Это можно сделать в TSQL с помощью xQuery, промежуточной таблицы и динамического pivot.

Промежуточная таблица:

create table dbo.XMLStage
(
  ID uniqueidentifier not null,
  Name nvarchar(128) not null,
  Value nvarchar(max) not null,
  primary key (Name, ID)
);

ID является уникальным для каждого файла, Name содержит имя узла и Value значение узла.

Хранимая процедура для заполнения промежуточной таблицы:

create procedure dbo.LoadXML
  @XML xml
as

declare @ID uniqueidentifier;
set @ID = newid();

insert into dbo.XMLStage(ID, Name, Value)
select @ID,
       T.X.value('local-name(.)', 'nvarchar(128)'),
       T.X.value('text()[1]', 'nvarchar(max)')
from @XML.nodes('//*[text()]') as T(X);

//*[text()] даст вам все узлы, которые имеют текстовое значение

Динамический запрос для удаления данных из промежуточной таблицы:

declare @Cols nvarchar(max);
declare @SQL nvarchar(max);

set @Cols = (
            select distinct ',' + quotename(X.Name)
            from dbo.XMLStage as X
            for xml path(''), type
            ).value('substring(text()[1], 2)', 'nvarchar(max)');

set @SQL = '
select '+@Cols+'
from dbo.XMLStage
pivot (max(Value) for Name in ('+@Cols+')) as P';

exec sp_executesql @SQL;

Попробуйте это в этой скрипке SQL

Comments

    Ничего не найдено.