C#将重复的XML标记放入DataTable
我有一个XML文件,我正试图解析它并将其保存到C#程序中的数据库中。对于该文件中的大多数元素,我都能够使用SqlBulkCopy,因为这些元素都是以子标记的唯一名称或根节点上的属性进行排列的。但是,我有一个元素,它的子元素具有重复的标记名(只是“标记”),但使用属性名来描述它是什么。我还不能用SqlBulkCopy保存这个文件,我更喜欢用SqlBulkCopy,因为这个文件可以大到500MB,而SqlBulkCopy类要快得多。我尝试了下面的代码,但通过调试可以看出ds.Tables集合正在分离hostproperties和标记。我猜这就是ReadXml方法的工作原理。最简单的方法是什么,我可以将这些标记放入一个datatable对象中,该对象具有作为列的各个属性,以便使用SqlBulkCopy 当前C#代码C#将重复的XML标记放入DataTable,c#,xml,dataset,sqlbulkcopy,C#,Xml,Dataset,Sqlbulkcopy,我有一个XML文件,我正试图解析它并将其保存到C#程序中的数据库中。对于该文件中的大多数元素,我都能够使用SqlBulkCopy,因为这些元素都是以子标记的唯一名称或根节点上的属性进行排列的。但是,我有一个元素,它的子元素具有重复的标记名(只是“标记”),但使用属性名来描述它是什么。我还不能用SqlBulkCopy保存这个文件,我更喜欢用SqlBulkCopy,因为这个文件可以大到500MB,而SqlBulkCopy类要快得多。我尝试了下面的代码,但通过调试可以看出ds.Tables集合正在分离
DataSet ds = new DataSet();
ds.ReadXml(file.InputStream);
DataTable hostItems = ds.Tables["host"];
conn.Open();
using (SqlBulkCopy sb = new SqlBulkCopy(conn))
{
sb.DestinationTableName = "HOSTS";
sb.ColumnMappings.Add("host-ip", "HOST_IP");
sb.ColumnMappings.Add("host-name", "NAME");
sb.ColumnMappings.Add("system-type", "SSH_FINGERPRINT");
sb.ColumnMappings.Add("os", "OS");
sb.WriteToServer(hostItems);
}
<host>
<tag name="host-ip">192.168.200.8</tag>
<tag name="host-name">someserver.mydomain.com</tag>
<tag name="system-type">webserver</tag>
<tag name="os">WindowsServer2019</tag>
</host>
...
<host>
<tag name="host-ip">192.168.200.9</tag>
<tag name="host-name">someserver2.mydomain.com</tag>
<tag name="system-type">webserver</tag>
<tag name="os">WindowsServer2019</tag>
<tag name="attributeFirstOneDidntHave">Some nonsense</tag>
</host>
XML文件
DataSet ds = new DataSet();
ds.ReadXml(file.InputStream);
DataTable hostItems = ds.Tables["host"];
conn.Open();
using (SqlBulkCopy sb = new SqlBulkCopy(conn))
{
sb.DestinationTableName = "HOSTS";
sb.ColumnMappings.Add("host-ip", "HOST_IP");
sb.ColumnMappings.Add("host-name", "NAME");
sb.ColumnMappings.Add("system-type", "SSH_FINGERPRINT");
sb.ColumnMappings.Add("os", "OS");
sb.WriteToServer(hostItems);
}
<host>
<tag name="host-ip">192.168.200.8</tag>
<tag name="host-name">someserver.mydomain.com</tag>
<tag name="system-type">webserver</tag>
<tag name="os">WindowsServer2019</tag>
</host>
...
<host>
<tag name="host-ip">192.168.200.9</tag>
<tag name="host-name">someserver2.mydomain.com</tag>
<tag name="system-type">webserver</tag>
<tag name="os">WindowsServer2019</tag>
<tag name="attributeFirstOneDidntHave">Some nonsense</tag>
</host>
192.168.200.8
someserver.mydomain.com
网络服务器
WindowsServer2019
...
192.168.200.9
someserver2.mydomain.com
网络服务器
WindowsServer2019
胡说八道
编辑
我没有提到不是所有的主机都有相同数量的标签。我已经更新了XML示例来说明这一点。对于庞大的XML文件,您需要使用XmlReader,否则将出现内存不足错误。下面的代码使用xmlreader和XMLLINQ的组合
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
XmlReader reader = XmlReader.Create(FILENAME);
long count = 0;
while (!reader.EOF)
{
if (reader.Name != "host")
{
reader.ReadToFollowing("host");
}
if (!reader.EOF)
{
XElement host = (XElement)XElement.ReadFrom(reader);
if (++count == 1)
{
foreach (XElement tag in host.Elements("tag"))
{
dt.Columns.Add((string)tag.Attribute("name"),typeof(string));
}
}
DataRow row = dt.Rows.Add();
foreach (XElement tag in host.Elements("tag"))
{
row[(string)tag.Attribute("name")] = (string)tag;
}
}
}
}
}
}
XML是一种关系结构,这就是为什么要为
host
和tag
获取一个表。主机被视为一个具有相关标记“entities”的“entity”。一个选项是将主机/标记关系展平到一个新的数据集中,并将其传递给您的批量复制方法。这为我指明了正确的方向,并且似乎具有大致相同的效率。但是,有一个问题:我如何使用此方法在一次过程中读取多个节点?假设我正在寻找这个主机节点和其他两个不同级别的节点(例如,硬件和安装的软件)?我会使用ReadToFollowing以外的东西吗?我已经试了好几次了,结果变得一团糟。我需要解析一个巨大的SVG文件,并使用ReadToFollow在不同节点之间进行转换。我认为最好的方法就是使用一个普通的父母。