如何将数据表导出到 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

如何将数据表导出到 Sqml,并将所有列作为属性

必须为每个 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;
}