【问题标题】:Merge XML Dataset Datatables into one Datatable将 XML 数据集数据表合并为一个数据表
【发布时间】:2018-03-02 20:05:43
【问题描述】:

我需要使用 C# 解析 XML 文档以将数据导入数据库。

目前,我正在使用 SSIS 和此 C# 代码将文档读入数据集:

var xmlString = File.ReadAllText(Variables.filepath);
var stringReader = new StringReader(xmlString);
var dsSet = new DataSet();
dsSet.ReadXml(stringReader);

这可以完美地读取 XML,但它会将其分解为具有关系的多个表。有没有办法将所有数据表合并到一个表中,这样我就可以将所有数据表都放入一个 SQL 表中?

XML 示例:

关系示例:

【问题讨论】:

  • 你能说明它是如何分解的吗?
  • 不幸的是,数据本身是敏感的。但是,本文档中的硬件清单数据对此进行了说明:en.community.dell.com/techcenter/extras/m/white_papers/20270305
  • 好吧,您可以根据自己的意愿审查数据,需要一个最小、完整和可验证的示例:stackoverflow.com/help/mcve
  • @hellyale 我提供的图片有帮助吗?
  • DataSet ReadXml 方法仅适用于有限数量的后代。该方法使用根标签作为数据集名称。下一级标记数据表名称。下一级标签是列名。第四级标签是行数据。一旦您获得超过 4 个级别的标签,该方法就会创建无法轻松重新组合的碎片表。所以我通常手动编写代码,使用 xml linq 将结果放入一个可用的数据表中。如果您发布示例 xml 的文本版本,我可以在几分钟内完成。很简单。

标签: c# xml datatable ssis


【解决方案1】:

尝试以下:

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();
            dt.Columns.Add("Message Id", typeof(string));
            dt.Columns.Add("Protocol Version", typeof(string));
            dt.Columns.Add("Name Instance URL", typeof(string));
            dt.Columns.Add("Classname", typeof(string));
            dt.Columns.Add("Key Binding", typeof(string));
            dt.Columns.Add("Key Value", typeof(string));
            dt.Columns.Add("Property Name", typeof(string));
            dt.Columns.Add("Value", typeof(string));
            dt.Columns.Add("Display Value", typeof(string));

            XDocument doc = XDocument.Load(FILENAME);

            XElement cim = doc.Root;
            XElement message = cim.Element("MESSAGE");
            List<XElement> values = message.Descendants("VALUE.NAMEDINSTANCE").ToList();


            string messageId = (string)message.Attribute("ID");
            string version = (string)message.Attribute("PROTOCOLVERSION");

            foreach (XElement value in values)
            {
                string url = value.GetNamespaceOfPrefix("fo").NamespaceName;

                XElement instanceName = value.Element("INSTANCENAME");
                string classname = (string)instanceName.Attribute("CLASSNAME");
                string binding = (string)instanceName.Element("KEYBINDING").Attribute("NAME");
                string key = (string)instanceName.Descendants("KEYVALUE").FirstOrDefault();
                XElement instance = value.Element("INSTANCE");
                foreach (XElement valueArray in instance.Descendants("VALUE.ARRAY"))
                {
                    dt.Rows.Add(new object[] {
                        messageId,
                        version,
                        url,
                        classname,
                        binding,
                        key,
                        (string)valueArray.Attribute("NAME"),
                        (string)valueArray.Element("VALUE"),
                        (string)valueArray.Element("DisplayValue")
                    });
                }
                foreach (XElement property in instance.Elements("PROPERTY"))
                {
                    dt.Rows.Add(new object[] {
                        messageId,
                        version,
                        url,
                        classname,
                        binding,
                        key,
                        (string)property.Attribute("NAME"),
                        (string)property.Element("VALUE"),
                        (string)property.Element("DisplayValue")
                    });

                }
            }
        }
    }
}

我用来测试的xml

<?xml version="1.0"?>
<CIM CIMVERSION="2.0" DTDVERSION="2.0">
  <MESSAGE ID="4711" PROTOCOLVERSION="1.0">
    <SIMPLEREQ>
      <VALUE.NAMEDINSTANCE xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <INSTANCENAME CLASSNAME="DCIM_ControllerView">
          <KEYBINDING NAME="InstanceID">
            <KEYVALUE VALUETYPE="string">RAID.Slot.1-1</KEYVALUE>
          </KEYBINDING>
        </INSTANCENAME>
        <INSTANCE CLASSNAME="DCIM_ControllerView">
          <PROPERTY NAME="DriverVersion" TYPE="string">
            <DisplayValue/>
          </PROPERTY>
          <PROPERTY NAME="KeyID" TYPE="string">
            <DisplayValue/>
          </PROPERTY>
          <PROPERTY NAME="SASAddress" TYPE="string">
            <VALUE>5782BCB00C577600</VALUE>
            <DisplayValue>5782BCB00C577600</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="ProductName" TYPE="string">
            <VALUE>PERC H310 Adapter</VALUE>
            <DisplayValue>
              PERC
              H310 Adapter
            </DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="DeviceCardSlotType" TYPE="string">
            <VALUE>PCI Express x8</VALUE>
            <DisplayValue>
              PCI Express
              x8
            </DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="DeviceCardManufacturer" TYPE="string">
            <VALUE>DELL</VALUE>
            <DisplayValue>DELL</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCISubDeviceID" TYPE="string">
            <VALUE>1F4E</VALUE>
            <DisplayValue>1F4E</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCIDeviceID" TYPE="string">
            <VALUE>73</VALUE>
            <DisplayValue>73</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCISubVendorID" TYPE="string">
            <VALUE>1028</VALUE>
            <DisplayValue>1028</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCIVendorID" TYPE="string">
            <VALUE>1000</VALUE>
            <DisplayValue>1000</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Function" TYPE="string">
            <VALUE>0</VALUE>
            <DisplayValue>0</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Device" TYPE="string">
            <VALUE>0</VALUE>
            <DisplayValue>0</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Bus" TYPE="string">
            <VALUE>1</VALUE>
            <DisplayValue>1</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="ControllerFirmwareVersion" TYPE="string">
            <VALUE>20.10.1-0066</VALUE>
            <DisplayValue>
              20.10.1-
              0066
            </DisplayValue>
          </PROPERTY>
        </INSTANCE>
      </VALUE.NAMEDINSTANCE>
      <VALUE.NAMEDINSTANCE xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <INSTANCENAME CLASSNAME="DCIM_ControllerView">
          <KEYBINDING NAME="InstanceID">
            <KEYVALUE VALUETYPE="string">RAID.Slot.1-1</KEYVALUE>
          </KEYBINDING>
        </INSTANCENAME>
        <INSTANCE CLASSNAME="DCIM_ControllerView">
          <PROPERTY NAME="DriverVersion" TYPE="string">
            <DisplayValue/>
          </PROPERTY>
          <PROPERTY NAME="KeyID" TYPE="string">
            <DisplayValue/>
          </PROPERTY>
          <PROPERTY NAME="SASAddress" TYPE="string">
            <VALUE>5782BCB00C577600</VALUE>
            <DisplayValue>5782BCB00C577600</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="ProductName" TYPE="string">
            <VALUE>PERC H310 Adapter</VALUE>
            <DisplayValue>
              PERC
              H310 Adapter
            </DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="DeviceCardSlotType" TYPE="string">
            <VALUE>PCI Express x8</VALUE>
            <DisplayValue>
              PCI Express
              x8
            </DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="DeviceCardManufacturer" TYPE="string">
            <VALUE>DELL</VALUE>
            <DisplayValue>DELL</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCISubDeviceID" TYPE="string">
            <VALUE>1F4E</VALUE>
            <DisplayValue>1F4E</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCIDeviceID" TYPE="string">
            <VALUE>73</VALUE>
            <DisplayValue>73</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCISubVendorID" TYPE="string">
            <VALUE>1028</VALUE>
            <DisplayValue>1028</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="PCIVendorID" TYPE="string">
            <VALUE>1000</VALUE>
            <DisplayValue>1000</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Function" TYPE="string">
            <VALUE>0</VALUE>
            <DisplayValue>0</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Device" TYPE="string">
            <VALUE>0</VALUE>
            <DisplayValue>0</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="Bus" TYPE="string">
            <VALUE>1</VALUE>
            <DisplayValue>1</DisplayValue>
          </PROPERTY>
          <PROPERTY NAME="ControllerFirmwareVersion" TYPE="string">
            <VALUE>20.10.1-0066</VALUE>
            <DisplayValue>
              20.10.1-
              0066
            </DisplayValue>
          </PROPERTY>
        </INSTANCE>
      </VALUE.NAMEDINSTANCE>

    </SIMPLEREQ>
  </MESSAGE>
</CIM>

【讨论】:

  • 你能解释一下这里到底发生了什么吗?此外,当我粘贴代码时,它无法识别 XDocument 和 XElement
  • 您需要在模块顶部添加: using System.Xml.Linq;我制作了一个包含 9 列的数据表。然后使用 dt.Rows.Add(new object[] {...} 在表中为每个出现的元素“属性”创建一个新行。数据以与定义列相同的顺序添加到行中。
  • 我得到:System.Xml.Linq.XElement.GetNamespaceOfPrefix(...) 返回 null。 “fo”是干什么用的?
  • 没关系,看起来我的示例 XML 与我的实际 XML 不完全匹配。谢谢你的代码。
  • fo 是命名空间的前缀名称。您可以消除任何不需要的列。我只是解析了所有内容,因此您可以看到如何获取所有元素的示例。
猜你喜欢
  • 2016-04-07
  • 2011-02-21
  • 2014-12-18
  • 1970-01-01
  • 2019-05-02
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 2020-04-27
相关资源
最近更新 更多