使用C#(或任何其他方法)将XML转换为SQL Server表

时间:2014-04-24 18:12:43

标签: c# sql sql-server xml

我有大约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#,如果有人能提出更好的方法,请告诉我。

2 个答案:

答案 0 :(得分:2)

迭代所有xml文件并获取所有唯一标记的一种可能性可以使用LINQ2XML HashSet class,看起来像这样:

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表的。几乎没有增强,您还可以标记父节点和子节点。这可以帮助您进行规范化。

答案 1 :(得分:1)

您可以使用xQuery,临时表和动态数据透视表在TSQL中执行此操作。

临时表:

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 Fiddle

中试用