这就是我的xml看起来像
的样子<?xml version="1.0" encoding="utf-8"?>
<Root>
<orders>
<OrderID>10248</OrderID>
<CustomerID>VINET</CustomerID>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04T00:00:00</OrderDate>
<RequiredDate>1996-08-01T00:00:00</RequiredDate>
<ShippedDate>1996-07-16T00:00:00</ShippedDate>
<ShipVia>3</ShipVia>
<Freight>32.3800</Freight>
<ShipName>Vins et alcools Chevalier</ShipName>
<ShipAddress>59 rue de l'Abbaye</ShipAddress>
<ShipCity>Reims</ShipCity>
<ShipPostalCode>51100</ShipPostalCode>
<ShipCountry>France</ShipCountry>
</orders>
</Root>
我用LINQ这样解析上面的xml
document.Descendants("orders").Select(c => c).ToList()
我想以表格格式列出xml数据,就像sql查询返回数据一样。
我搜索并获得了一个链接http://stackoverflow.com/questions/18608959/convert-linq-query-results-to-datatable-c-sharp
建议使用CopyToDataTable() extension
方法的链接,但我仍未获得表格格式的结果。
所以请指导我如何转换我的ToList() to Datatable
,结果输出看起来像
OrderID CustomerID EmployeeID
------- ---------- -----------
10248 VINET 5
10249 AJAY 11
11027 Smith 09
public static class DataSetLinqOperators
{
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
{
return new ObjectShredder<T>().Shred(source, null, null);
}
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
DataTable table, LoadOption? options)
{
return new ObjectShredder<T>().Shred(source, table, options);
}
}
public class ObjectShredder<T>
{
private FieldInfo[] _fi;
private PropertyInfo[] _pi;
private Dictionary<string, int> _ordinalMap;
private Type _type;
public ObjectShredder()
{
_type = typeof(T);
_fi = _type.GetFields();
_pi = _type.GetProperties();
_ordinalMap = new Dictionary<string, int>();
}
public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options)
{
if (typeof(T).IsPrimitive)
{
return ShredPrimitive(source, table, options);
}
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
// now see if need to extend datatable base on the type T + build ordinal map
table = ExtendTable(table, typeof(T));
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
while (e.MoveNext())
{
if (options != null)
{
table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
}
else
{
table.LoadDataRow(ShredObject(table, e.Current), true);
}
}
}
table.EndLoadData();
return table;
}
public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options)
{
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
if (!table.Columns.Contains("Value"))
{
table.Columns.Add("Value", typeof(T));
}
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
Object[] values = new object[table.Columns.Count];
while (e.MoveNext())
{
values[table.Columns["Value"].Ordinal] = e.Current;
if (options != null)
{
table.LoadDataRow(values, (LoadOption)options);
}
else
{
table.LoadDataRow(values, true);
}
}
}
table.EndLoadData();
return table;
}
public DataTable ExtendTable(DataTable table, Type type)
{
// value is type derived from T, may need to extend table.
foreach (FieldInfo f in type.GetFields())
{
if (!_ordinalMap.ContainsKey(f.Name))
{
DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
: table.Columns.Add(f.Name, f.FieldType);
_ordinalMap.Add(f.Name, dc.Ordinal);
}
}
foreach (PropertyInfo p in type.GetProperties())
{
if (!_ordinalMap.ContainsKey(p.Name))
{
DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
: table.Columns.Add(p.Name, p.PropertyType);
_ordinalMap.Add(p.Name, dc.Ordinal);
}
}
return table;
}
public object[] ShredObject(DataTable table, T instance)
{
FieldInfo[] fi = _fi;
PropertyInfo[] pi = _pi;
if (instance.GetType() != typeof(T))
{
ExtendTable(table, instance.GetType());
fi = instance.GetType().GetFields();
pi = instance.GetType().GetProperties();
}
Object[] values = new object[table.Columns.Count];
foreach (FieldInfo f in fi)
{
values[_ordinalMap[f.Name]] = f.GetValue(instance);
}
foreach (PropertyInfo p in pi)
{
values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
}
return values;
}
}
然后以这种方式调用DataTable dtt =document.Descendants("orders").Select(c => c).ToList().CopyToDataTable();
,但它没有按照我想要的方式工作。
答案 0 :(得分:1)
Microsoft发布了一个非常可靠且快速的示例类(快速,基于反射的解决方案可以)。
它被称为ObjectShredder
,您可以从msdn
最适合使用此ExtensionMethod
public static class CustomLINQtoDataSetMethods
{
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
{
return new ObjectShredder<T>().Shred(source, null, null);
}
public static DataTable CopyToDataTable<T>(
this IEnumerable<T> source, DataTable table, LoadOption? options)
{
return new ObjectShredder<T>().Shred(source, table, options);
}
}
但是,由于document.Descendants("orders")
返回的XElement
类型不具备有用的属性,但有些XElements我会建议您使用匿名类型。
用法:
var query = from o in document.Descendants("orders")
select new
{
OrderID = (int)o.Element("OrderID"),
CustomerID = (string)o.Element("CustomerID"),
EmployeeID = (int)o.Element("EmployeeID"),
};
var table = query.ToDataTable();
答案 1 :(得分:1)
我还无法添加评论,所以在这里你可以做什么
基于以下thread
中的答案您需要引用FastMember
public static DataTable ToDataTable<T>(this IEnumerable<T> data)
{
if (data == null)
throw new ArgumentNullException("data");
var table = new DataTable("sd");
using (var reader = ObjectReader.Create(data))
{
table.Load(reader);
}
return table;
}
如果您正在使用DataContext(linq-to-sql)
public static DataTable ToDataTable<T>(this IQueryable<T> query, DataContext context)
{
if (query == null)
{
throw new ArgumentNullException("query");
}
IDbCommand cmd = context.GetCommand(query.AsQueryable());
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = (SqlCommand)cmd;
DataTable dt = new DataTable("sd");
try
{
cmd.Connection.Open();
adapter.FillSchema(dt, SchemaType.Source);
adapter.Fill(dt);
}
finally
{
cmd.Connection.Close();
}
return dt;
}
<强>已更新强>
您可以使用以下功能
public static DataTable ConvertToDataTable(IEnumerable<XElement> data)
{
var table = new DataTable();
// create the columns
foreach(var xe in data.First().Descendants())
table.Columns.Add(xe.Name.LocalName,typeof(string));
// fill the data
foreach(var item in data)
{
var row = table.NewRow();
foreach(var xe in item.Descendants())
row[xe.Name.LocalName] = xe.Value;
table.Rows.Add(row);
}
return table;
}
并使用该功能
var table = ConvertToDataTable(document.Descendants("orders"));
此处正在工作sample
答案 2 :(得分:0)
使用readxml将xml转换为数据选项卡。例如,下面的值是IEnumerable类型
com.android.support:appcompat-v7:22.2.0