使用C#(或任何其他方法)将XML转换为SQL Server表
本文关键字:转换 XML SQL Server 任何 方法 其他 使用 | 更新日期: 2023-09-27 17:59:50
我有大约10000个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#,但如果有人能提出更好的方法,请告诉我。
迭代所有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、一个临时表和动态透视表来实现这一点。
暂存表:
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 中试用它