C# 获取重复 XML 标签到 DataTable

C# Get repeating XML tags into DataTable

我有一个 XML 文件,我试图在 C# 程序中解析并保存到数据库中。对于此文件中的大多数元素,我已经能够使用 SqlBulkCopy,因为这些元素排列得很好,子标签的唯一名称或根节点上的属性。但是,我有一个元素的子元素带有重复的标签名称(只是“标签”),但使用属性名称来描述它是什么。我无法使用 SqlBulkCopy 保存它,我更喜欢使用 SqlBulkCopy,因为这个文件可以大到 500MB,而 SqlBulkCopy class 更快。我尝试了下面的代码,但通过调试可以看到 ds.Tables 集合正在分离主机属性和标签。我猜这就是 ReadXml 方法的工作原理。将这些标记放入一个数据表对象中的最简单方法是什么,该数据表对象将各个属性作为列,以便我可以使用 SqlBulkCopy?

当前 C# 代码

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);
 }

XML 文件

<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 示例来说明这一点。

对于巨大的 xml 文件,您需要使用 XmlReader,否则,您将遇到内存不足的错误。下面的代码使用了 xmlreader 和 xml linq

的组合
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;
                    }

                }
            }
        }
    }
}