XML将属性

时间:2017-07-14 00:10:18

标签: c# xml datatable attributes

是否有更优雅的方式从XML文件中提取数据,该文件将其字段和数据完全存储在属性中?

我已经尝试了一个多月来从通过API获取的XML文件中提取数据,将其转换为DataTable,我使用C#,Visual Studio和.Net类来实现这一目标(特别是DOMDocument60,因为我发现的大多数例子都使用了它。)

使用任何这些示例都难以使用XML文件,因为它不是将数据存储在文本中而是存储在属性中。这是所有数据的返回方式:

<result>
    <record>
        <field name="donor_id" id="donor_id" value="33750"/>
        <field name="first_name" id="first_name" value="Jacob"/>
        <field name="last_name" id="last_name" value="LaBay"/>
    </record>
    <record>
        <field name="donor_id" id="donor_id" value="33750"/>
        <field name="first_name" id="first_name" value="Jacob"/>
        <field name="last_name" id="last_name" value="LaBay"/>
    </record>
</result>

正如您将看到的,字段名称位于&#34; name&#34;和&#34; id&#34;属性,值在&#34;值&#34;。

我尝试过的方法(下面)是首先通过迭代整个文件来获取列,查看&#34; id&#34;元素,并将它们作为列添加到DataTable,如果它们已经是列,则忽略它们,然后在添加列之后,解析具有&#34; value&#34;属性的所有元素,并添加它们作为该DataTable的行。问题是它效率低下(它需要在整个文件中继续查找可能的列,即使它在开头已经有了它),而且它也有错误 - 它经常崩溃。所以它很慢而且不稳定,而且我可以运行一些大的返回结果(我可以将API字符串输入到浏览器中,但看起来问题不在于XML,而是我的代码,正在解析它。)

以下是我提出的用于首先确定数据列的代码,然后是添加行的方法(该对象具有DataSet作为属性):

    public void ProduceDataColumns()
    {
        DataTable table = new DataTable();
        this.DataSet = new DataSet();

        IXMLDOMNodeList objNodeList;

        objNodeList = this.XMLDoc.selectNodes("//field");

        foreach (IXMLDOMNode objNode in objNodeList)
        {                
            if (objNode.nodeType == DOMNodeType.NODE_ELEMENT)
            {
                String str = objNode.attributes.getNamedItem("name").nodeValue;
                String str2 = str.Replace("_", "__");

                if (!table.Columns.Contains(str2))
                {

                    table.Columns.Add(str2);
                }
            }                             
        }
        this.DataSet.Tables.Add(table);
    }

    public void ProduceDataRows()
    {
        IXMLDOMNodeList objNodeList;

        objNodeList = this.XMLDoc.selectNodes("//record");

        int i;
        IXMLDOMNode objNode = objNodeList[0];

        for (i = 0; i < objNodeList.length; i++)
        {
            object[] array = new object[objNode.childNodes.length];
            //DataRow dataRow = new DataRow();
            int j;
            for (j = 0; j < objNode.childNodes.length; j++)
            {
                array[j] = objNodeList[i].childNodes[j].attributes.getNamedItem("value").nodeValue;
            }
            this.DataSet.Tables[0].Rows.Add(array);
        }
    }

如果有人能帮我提出更好的解决方法,我会永远感激不尽。我仍然对解析可用的XML文档的无数方法感到困惑。如果您需要更多信息,请与我们联系。

更新:我尝试了jdweng的方法,但它导致了一种对角线的数据分布。我觉得这个foreach已经缺失了,但我已经搞了一段时间并且无法使用它(我仍然对Linq感到困惑)。

以下是WPF DataGrid中DataSet的图像:

enter image description here

1 个答案:

答案 0 :(得分:1)

这是使用已发布的xml开始的代码。我认为当你发布更好的xml输入样本时,他的代码需要修改。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;

namespace ConsoleApplication65
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            string[] uniqueIds = doc.Descendants("field").Select(x => (string)x.Attribute("id")).Distinct().ToArray();

            DataTable dt = new DataTable();
            foreach (string col in uniqueIds)
            {
                dt.Columns.Add(col, typeof(string));
            }

            foreach (XElement record in doc.Descendants("record"))
            {
                DataRow row = dt.Rows.Add();
                foreach (XElement field in record.Elements("field"))
                {
                    row[(string)field.Attribute("id")] = (string)field.Attribute("value");
                }
            }

        }
    }

}
相关问题