4

使用 XDocument 写入 XML,但知道在哪里写入 类似于此 Qn。

希望你能帮助我一点。我正在尝试更新 XML 文件,但正在努力编写写入 XML 文件的方法。这是 XML 文件

  <software>
    <software_entry name="Adobe Acrobat X Standard" path="Applications\Acrobat\Acrobat XStandard\AcroStan.msi" />
    ..
  </software>
  <ApplicationConfigurations>
     <Config name ="someName" value ="someValue"/>
      ..
  </ApplicationConfigurations>

这里用户可以更改/添加标签,即software_entry下的名称或路径是未知的,因为用户可以编辑/添加值。除了格式,一切都是未知的。

我能够读取文件,将其存储在 中DataTable,填充到网格等。使用 LINQ

但是,在写入 xml 时编辑表格后,我被卡住了..

任何人都可以帮我将这种数据写入xml吗?

到目前为止,我已经尝试过:

for (int i = 0; i < dt.Length; i++) //for every table 
{
      XName TableName = dt[i].TableName; //table name.

      XElement[] xInnerElt = new XElement[dt[i].Rows.Count]; //for n rows inside one table
      for (int j = 0; j < dt[i].Rows.Count; j++) //loop each tag inside the table
      {
         XName InnerTagName = htAtributNameForTable[dt[i].TableName].ToString(); //tag name form hash table. i.e, software_entry
         //I am unable to write the next line
         xInnerElt[j] = new XElement(InnerTagName,new XAttribute((XName)ColumnName,rows Item arry)),
         //loop till all column added
      }

      XElement xElt = new XElement(TableName, xInnerElt); //one table aded to tag.
}
4

3 回答 3

3

使用此扩展方法,您可以将 any 转换DataTableXElement

public static class Extensions
{
    public static XElement ToXml(this DataTable table, string rowElementName)
    {
        // check if table has name and rowElementName is not empty           

        return new XElement(
            new XElement(table.TableName,
                from row in table.AsEnumerable()
                select new XElement(rowElementName,
                    from column in table.Columns.Cast<DataColumn>()
                    let value = row.Field<string>(column)
                    where value != null
                    select new XAttribute(column.Caption, value)
                    )
                )
            );
    }
}

用法:

DataTable table = new DataTable("software");
table.Columns.Add("name");
table.Columns.Add("path");
// add rows to table

XElement software = table.ToXml("software_element");
于 2013-03-14T14:01:46.987 回答
2

问题:

您在评论中声明您不确定如何添加将在生成的 XML 中创建属性的内部元素。您的代码的其余部分工作完美,除了这一点:

 //I am unable to write the next line
     xInnerElt[j] = new XElement(InnerTagName,new XAttribute((XName)ColumnName,rows Item arry)),

解决方案

您想要的缺失部分是遍历 上的列DataTable,然后访问每行列的值。这是因为该DataRow对象没有关于列名的信息。

因此,您需要通过集合进行另一个内部循环DataTable.Columns,然后使用DataRow列访问器dt.Rows[j][column]从当前列中获取值。

它看起来像这样:

              foreach (var column in dt[i].Columns)
              {
                  xInnerElt[j].Add(
                      new XAttribute(
                          (column as DataColumn).ColumnName,
                          dt[i].Rows[j][(column as DataColumn)].ToString()
                      )
                  );
              }

我对您的代码的测试:

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

namespace XElemFromDT
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, string> htAtributNameForTable = new Dictionary<string, string>()
            {
                { "Software", "software_entry" },
                { "ApplicationConfigurations", "config" }
            };

            DataTable dt1 = new DataTable();
            dt1.TableName = "Software";
            dt1.Columns.Add("name", typeof(string));
            dt1.Columns.Add("path", typeof(string));
            dt1.Rows.Add("Adobe Acrobat X Standard", @"Applications\Acrobat\Acrobat XStandard\AcroStan.msi");
            dt1.Rows.Add("Adobe Photoshop", @"Applications\Photoshop\Photoshop.msi");

            DataTable dt2 = new DataTable();
            dt2.TableName = "ApplicationConfigurations";
            dt2.Columns.Add("name", typeof(string));
            dt2.Columns.Add("value", typeof(string));
            dt2.Rows.Add("someName", "someValue");
            dt2.Rows.Add("someOtherName", "someOtherValue");

            DataTable[] dt = new DataTable[] { dt1, dt2 };

            XDocument xDoc = new XDocument(new XElement("Root"));

            for (int i = 0; i < dt.Length; i++) //for every table 
            {

                  XName TableName = dt[i].TableName; //table name.

                  XElement[] xInnerElt = new XElement[dt[i].Rows.Count]; //for n rows inside one table
                  for (int j = 0; j < dt[i].Rows.Count; j++) //loop each tag inside the table
                  {
                     XName InnerTagName = htAtributNameForTable[dt[i].TableName].ToString(); //tag name form hash table. i.e, software_entry
                     //I am unable to write the next line
                     xInnerElt[j] = new XElement(InnerTagName);

                      foreach (var column in dt[i].Columns)
                      {
                          xInnerElt[j].Add(
                              new XAttribute(
                                  (column as DataColumn).ColumnName,
                                  dt[i].Rows[j][(column as DataColumn)].ToString()
                              )
                          );
                      }
                  }

                  XElement xElt = new XElement(TableName, xInnerElt); //one table aded to tag.
                  xDoc.Root.Add(xElt);
            }

            Console.WriteLine(xDoc.ToString());
            Console.ReadKey();
        }
    }
}

奖金——因为我必须试试这个

这是一种完全使用 LINQ 的方法:(使用与我之前的示例相同的测试数据)

    DataTable[] dt = new DataTable[] { dt1, dt2 };

    XDocument xDoc = new XDocument(new XElement("Root"));

    Func<DataTable, DataRow, IEnumerable<XAttribute>> getAttributes = (t, r) =>
        t.Columns.OfType<DataColumn>().Select(c => new XAttribute(c.ColumnName, r[c].ToString()));

    Func<DataTable, IEnumerable<XElement>> getElements = t =>
        t.Rows.OfType<DataRow>().Select(r => new XElement(htAtributNameForTable[t.TableName], getAttributes(t, r)));

    Func<DataTable[], IEnumerable<XElement>> getTables = dtc =>
        dtc.AsEnumerable().Select(t => new XElement(t.TableName, getElements(t)));

    xDoc.Root.Add(getTables(dt));
于 2013-03-14T12:20:42.423 回答
1

如果您只是在寻找一种将 XElements 流式传输到文件的方法,那非常简单:

        using (XmlWriter writer = XmlWriter.Create("filename.xml"))
        {
            writer.WriteStartElement("DocumentElementName");
            // Your code goes here
            xElt.WriteTo(writer);
            writer.WriteEndElement();
        }
于 2013-03-14T12:08:18.983 回答