如何将所有列作为属性将DataTable导出到Xml?
问题:我正在将System.Data.DataTable导出到XML。 到目前为止,它工作正常。 但我想拥有属性中的所有数据,这也很好。 但现在我的问题,如果在一列中,所有行都是NULL,没有写入空属性。 因此,如果我将XML读回数据表,它缺少这一列...如何将所有列作为属性将DataTable导出到Xml?
如何强制写入所有列,即使它们是空的?
(数据类型不necessarely字符串)
public void ExportTable(string strDirectory, DataTable dtt)
{
using (System.Data.DataSet ds = new System.Data.DataSet()) {
string strTable = dtt.TableName;
ds.Tables.Add(dtt);
ds.DataSetName = strTable;
// Move data to attributes
foreach (DataTable dt in ds.Tables) {
foreach (DataColumn dc in dt.Columns) {
dc.ColumnMapping = MappingType.Attribute;
}
}
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Indent = true;
//settings.Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1")
settings.Encoding = System.Text.Encoding.UTF8;
settings.CloseOutput = true;
settings.CheckCharacters = true;
settings.NewLineChars = "\r\n";
// vbCr & vbLf
// Write as UTF-8 with indentation
using (System.Xml.XmlWriter w = System.Xml.XmlWriter.Create(System.IO.Path.Combine(strDirectory, strTable + ".xml"), settings)) {
// Strip out timezone
foreach (DataTable dt in ds.Tables) {
foreach (DataColumn dc in dt.Columns) {
if (object.ReferenceEquals(dc.DataType, typeof(DateTime))) {
dc.DateTimeMode = DataSetDateTime.Unspecified;
}
}
}
ds.Tables[0].WriteXml(w, XmlWriteMode.IgnoreSchema);
w.Flush();
w.Close();
}
// w
}
// ds
}
// ExportTable
VB.NET原:
Public Sub ExportTable(strDirectory As String, dtt As DataTable)
Using ds As New System.Data.DataSet()
Dim strTable As String = dtt.TableName
ds.Tables.Add(dtt)
ds.DataSetName = strTable
' Move data to attributes
For Each dt As DataTable In ds.Tables
For Each dc As DataColumn In dt.Columns
dc.ColumnMapping = MappingType.Attribute
Next dc
Next dt
Dim settings As New System.Xml.XmlWriterSettings()
settings.Indent = True
'settings.Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1")
settings.Encoding = System.Text.Encoding.UTF8
settings.CloseOutput = True
settings.CheckCharacters = True
settings.NewLineChars = vbCrLf ' vbCr & vbLf
' Write as UTF-8 with indentation
Using w As System.Xml.XmlWriter = System.Xml.XmlWriter.Create(System.IO.Path.Combine(strDirectory, strTable & ".xml"), settings)
' Strip out timezone
For Each dt As DataTable In ds.Tables
For Each dc As DataColumn In dt.Columns
If dc.DataType Is GetType(DateTime) Then
dc.DateTimeMode = DataSetDateTime.Unspecified
End If
Next dc
Next dt
ds.Tables(0).WriteXml(w, XmlWriteMode.IgnoreSchema)
w.Flush()
w.Close()
End Using ' w
End Using ' ds
End Sub ' ExportTable
每个XML属性必须赋值用一对单引号或双引号括起来。纯文本中没有等价物来表示NULL值。一对没有值表示空字符串的引号与NULL值不同。因此,表示NULL属性的唯一方法是省略该属性。
这意味着您需要将AllowDBNull
设置为false并在DataColumn上指定合适的DefaultValue
,或者包含模式。
另外,请参阅Handling Null Values (ADO.NET).,特别是这个部分,其说明了其行为:
此外,下列规则用于 的DataRow的一个实例[ “COLUMNNAME”]空赋值:
1 .The默认缺省值是DbNull.Value所有除强类型的空栏的地方是适当的强类型 空值。
2.Null值序列化到XML文件的过程中从来没有写出来(如“XSI:无”)。
3.所有非空值,包括默认值,总是写出来,而序列化到XML。这与XSD/XML语义其中 空值(XSI:无)是明确的,默认值是隐含的(如果 不存在XML,验证解析器可以从相关的 XSD架构得到它)。对于DataTable,情况正好相反:空值为 隐式,默认值为显式。
4.所有用于从XML输入读取的行缺失列值被分配NULL。使用NewRow或类似方法创建的行将被分配为 DataColumn的默认值。
5. isNull方法返回两个DbNull.Value和INullable.Null如此。
尝试列DefaultValue设置的东西有效
foreach (DataTable dt in ds.Tables) {
foreach (DataColumn dc in dt.Columns) {
dc.ColumnMapping = MappingType.Attribute;
//If type is DataType string
dc.DefaultValue = String.Empty;
}
两点:
第一: 的ExportTable()抛出一个异常:“数据表已属于另一个数据集。“当我执行:
ds.Tables.Add(dtt)
我通过使表的本地副本纠正了这个:
Dim dtX As DataTable = dtt.Copy
ds.Tables.Add(dtX)
ds.DataSetName = strTable
这行之有效
二: 如果使用XML来创建动态SQL语句中,不需要关心在XML导出中省略NULL值的列/字段。只需遍历XML记录中的属性,构建INSERT或UPDATE语句并执行连接命令这比usi快一个数据集。
对于INSERT它有一个缺点。如果通过增加标识列来创建主键,则ADO.Net DataSet将返回它。动态SQL将需要一个SELECT语句来检索它。
此外,混淆你的代码是个好主意。
这有点旧线程,但也许它可以帮助别人:
如果你不是经常写大的XML文件(可以导出设置或类似的东西),你可以使用下面的函数,否则最好使用cutom xml架构。
private static void addEmptyElementsToXML(DataSet dataSet)
{
foreach (DataTable dataTable in dataSet.Tables)
{
foreach (DataRow dataRow in dataTable.Rows)
{
for (int j = 0; j < dataRow.ItemArray.Length; j++)
{
if (dataRow.ItemArray[j] == DBNull.Value)
dataRow.SetField(j, string.Empty);
}
}
}
}
用法:
using(DataTable dTable = ..something..)
using(DataSet dS = new DataSet())
using(XmlTextWriter xmlStream = new XmlTextWriter("FILENAME.XML", Encoding.UTF8))
{
//set xml to be formatted so it can be easily red by human
xmlStream.Formatting = Formatting.Indented;
xmlStream.Indentation = 4;
//add table to dataset
dS.Tables.Add(dTable);
//call the mentioned function so it will set all DBNull values in dataset
//to string.Empty
addEmptyElementsToXML(dS);
//write xml to file
xmlStream.WriteStartDocument();
dS.WriteXml(xmlStream);
}
我一直在寻找全世界编写使用DataSet.WriteXML()空字段到XML的解决方案。我发现遵循性能优化的方式进行工作。为了您的方便,我创建了一个函数。通过调用以下函数并替换表格,一个接一个地更改数据集表。
private DataTable GetNullFilledDataTableForXML(DataTable dtSource)
{
// Create a target table with same structure as source and fields as strings
// We can change the column datatype as long as there is no data loaded
DataTable dtTarget = dtSource.Clone();
foreach (DataColumn col in dtTarget.Columns)
col.DataType = typeof(string);
// Start importing the source into target by ItemArray copying which
// is found to be reasonably fast for null operations. VS 2015 is reporting
// 500-525 milliseconds for loading 100,000 records x 10 columns
// after null conversion in every cell
// The speed may be usable in many circumstances.
// Machine config: i5 2nd Gen, 8 GB RAM, Windows 7 64bit, VS 2015 Update 1
int colCountInTarget = dtTarget.Columns.Count;
foreach (DataRow sourceRow in dtSource.Rows)
{
// Get a new row loaded with data from source row
DataRow targetRow = dtTarget.NewRow();
targetRow.ItemArray = sourceRow.ItemArray;
// Update DBNull.Values to empty string in the new (target) row
// We can safely assign empty string since the target table columns
// are all of string type
for (int ctr = 0; ctr < colCountInTarget; ctr++)
if (targetRow[ctr] == DBNull.Value)
targetRow[ctr] = String.Empty;
// Now add the null filled row to target datatable
dtTarget.Rows.Add(targetRow);
}
// Return the target datatable
return dtTarget;
}
使用XmlWriteMode.WriteSchema。在包含模式的情况下,它不会为null值添加属性。 – JamieSee 2012-04-19 15:58:24
@JamieSee:没有模式会更好,因为结果应该易于在任何编程语言中读取,而不仅仅是.NET。 – 2012-04-19 16:12:25