如何将所有列作为属性导出DataTable到Xml?

问题:我正在将System.Data.DataTable导出为XML。 到目前为止它工作正常。 但我希望在属性中包含所有数据,这也可以正常工作。 但我现在的问题是,如果在一列中,所有行都是NULL,则不会写入空属性。 因此,如果我将XML读回DataTable,它缺少此列…

即使它们是空的,我如何强制写入所有列?
(DataType不一定是字符串)

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 ,或者包含架构。

另请参阅处理空值(ADO.NET)。 ,特别是这部分解释了行为:

此外,以下规则适用于DataRow的实例。[“columnName”] null赋值:

1.除了强类型空列之外,默认默认值为DbNull.Value,其中它是适当的强类型空值。

2.在序列化到XML文件期间永远不会写出空值(如“xsi:nil”)。

3.在序列化为XML时,始终会写出所有非空值,包括默认值。 这与XSD / XML语义不同,其中空值(xsi:nil)是显式的,默认值是隐式的(如果不存在于XML中,则validation解析器可以从关联的XSD架构获取它)。 对于DataTable则相反:空值是隐式的,默认值是显式的。

4.从XML输入读取的行的所有缺失列值都指定为NULL。 使用NewRow或类似方法创建的行将分配DataColumn的默认值。

5.InNull方法对DbNull.Value和INullable.Null都返回true。

尝试将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()引发了一个exception:“DataTable已经属于另一个DataSet。” 当我执行时:

 ds.Tables.Add(dtt) 

我通过制作表的本地副本来纠正这个问题:

 Dim dtX As DataTable = dtt.Copy ds.Tables.Add(dtX) ds.DataSetName = strTable 

这很好用。

第二:如果使用XML创建动态SQL语句,则无需关注XML导出中忽略NULL值的列/字段。 只需遍历XML记录中的属性,构建INSERT或UPDATE语句并执行连接命令。 这比使用DataSet更快。

对于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的解决方案。 我发现以下是以性能优化的方式工作。 为方便起见,我创建了一个function。 通过调用以下函数并替换表,一个接一个地更改数据集表。

 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; }