如何将数据表导出到 Sqml,并将所有列作为属性
本文关键字:属性 Sqml 数据表 | 更新日期: 2023-09-27 18:31:51
问:我正在将System.Data.DataTable导出为XML。到目前为止,它工作正常。但是我想将所有数据都放在属性中,这也很好用。但是我现在的问题,如果在一列中,所有行都是 NULL,则不会写入空属性。因此,如果我将 XML 读回数据表,它缺少此列...
如何强制写入所有列,即使它们为空 ?
(数据类型不一定是字符串)
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 并在数据列上分配合适的DefaultValue
,或者包含架构。
另请参阅处理空值 (ADO.NET),特别是解释行为的本节:
此外,以下规则适用于 数据行。["列名称"] 空赋值:
1.默认默认值为 DbNull。除强类型空列之外的所有值,其中它是适当的强类型 空值。
2.在序列化为 XML 文件的过程中,永远不会写出空值(如"xsi:nil")。
3.序列化为 XML 时,始终写出所有非空值(包括默认值)。这与 XSD/XML 语义不同,其中 空值 (xsi:nil) 是显式的,默认值是隐式的(如果 XML 中不存在,验证解析器可以从关联的 XSD 架构)。对于数据表,情况正好相反:空值为 隐式,默认值为显式。
4.从 XML 输入读取的行的所有缺失列值都分配为 NULL。使用 NewRow 或类似方法创建的行被分配为 数据列的默认值。
5.IsNull 方法对 DbNull.Value 和 INullable.Null 都返回 true。
尝试将列默认值设置为有效值
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() 抛出了一个异常:"DataTable 已经属于另一个数据集。当我执行时:
ds.Tables.Add(dtt)
我通过制作表的本地副本来更正此问题:
Dim dtX As DataTable = dtt.Copy
ds.Tables.Add(dtX)
ds.DataSetName = strTable
这很有效。
第二:如果使用 XML 创建动态 SQL 语句,则无需担心 XML 导出中省略具有 NULL 值的列/字段。只需遍历 XML 记录中的 a 属性,生成 INSERT 或 UPDATE 语句并执行连接命令。这比使用数据集更快。
对于插入,它有一个缺点。如果主键是通过递增标识列创建的,则 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;
}