使用linq写入xml文件

时间:2013-03-14 11:29:12

标签: c# xml linq

Writing to XML using XDocument, but knowing where to write与此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.
}

3 个答案:

答案 0 :(得分:3)

使用此扩展程序,您可以将DataTable转换为XElement

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

答案 1 :(得分: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));

答案 2 :(得分:1)

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

        using (XmlWriter writer = XmlWriter.Create("filename.xml"))
        {
            writer.WriteStartElement("DocumentElementName");
            // Your code goes here
            xElt.WriteTo(writer);
            writer.WriteEndElement();
        }