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.
}
答案 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();
}