【问题标题】:DataTable.WriteXML() without verbose Namespace and DataType declarationsDataTable.WriteXML() 没有详细的命名空间和数据类型声明
【发布时间】:2014-06-16 20:20:03
【问题描述】:

我将一个简单的 DataTable 序列化为 XML,并将结果存储在一个字符串中。使用 StringWriter 和 DataTable.WriteToXml,一切正常。

public class Parameters
{   private DataTable ParamList = new DataTable();

    public Parameters()
    {   //Default constructor, build datatable with two empty columns
        ParamList.TableName = "Parameter";
        ParamList.Columns.Add("Name",Type.GetType("System.String"));
        ParamList.Columns.Add("Value",Type.GetType("System.Object")); }
    ...
    public string ConvertToXML()
    {   string result;
        using(var sw = new System.IO.StringWriter())
        {   ParamList.WriteXml(sw);
            result = sw.ToString();
        }
        return result;
    }
}

这如宣传的那样工作。但是,在定义字段时,XML 非常冗长:

<DocumentElement>
  <Parameter>
    <Name>ClientNumber</Name>
    <Value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">00001</Value>
  </Parameter>
  <Parameter>
    <Name>FirstName</Name>
    <Value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">John</Value>
  </Parameter>
  <Parameter>
    <Name>LastName</Name>
    <Value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Smith</Value>
  </Parameter>
...

我想消除 VALUE 字段中的所有命名空间和数据类型声明,就像出现 NAME 字段一样。我玩弄了 XmlWriterSettings(),但似乎找不到任何设置来完成此操作。有什么想法吗?我的建议可行吗?

(注 1:我的意图只是将数据表中的字段和值记录到 SQL 表中,并且由于字段和值的数量可能会有所不同,这似乎是最简单的方法。不会读取 XML回到过去,因此强类型数据元素对我的目标并不重要。)

(注 2:我想在不借助 RegEx 的情况下实现这一目标,但如果这是我唯一的选择,那可能是我采取的方向。)

可能重复? :Serialize into an XML Fragment - not XML Document

对此进行了调查,但无法调整语法以使用 DataTable。

【问题讨论】:

  • 你为什么关心它有多冗长?
  • 输出是供人使用的,我只是使用 XML 格式作为一种方便的方式来保持它的组织。
  • DataTable 为您提供手动生成最简单的 xml 文档所需的所有元数据。只需遍历行和列,将结果输出到 stringbuilder 或使用其中一个 xml api。
  • 听起来可以管理。我只是希望有一种内置的方法,利用 WriteXML() 函数而不是编写自定义解决方案。
  • 刚刚运行测试并确认生成命名空间声明的唯一原因是因为我将数据表的 VALUE 字段定义为对象,因此它可以接受任何数据类型。如果我把它改成字符串,我的问题就解决了,但它对我的程序的其余部分没有好处。

标签: c# .net xml


【解决方案1】:

这是我尝试过的完整程序 - 所以 Holder 用于保存任何东西并序列化值:

 public class Holder:IXmlSerializable
{
    public object Data { get; set; }
    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
    }

    public void WriteXml(XmlWriter writer)
    {
       writer.WriteString(Data.ToString());
    }
}
public class DataTableManager
{
    public static void Save()
    {
        DataTable dataTable = new DataTable("table1");
        DataColumn dataColumn = new DataColumn("Column1",typeof(string));
        DataColumn dataColumn2 = new DataColumn("Column2",typeof(Holder));
        dataTable.Columns.Add(dataColumn);
        dataTable.Columns.Add(dataColumn2);
        dataTable.Rows.Add("ro2", new Holder(){Data = 1});
        dataTable.Rows.Add("ro3", new Holder() { Data = "Test" });
        dataTable.Rows.Add("ro4", new Holder() { Data = new decimal(10) });

        Debug.WriteLine(dataTable.Namespace);
        //To file:
        dataTable.WriteXml(@"c:\development\datatable.xml",XmlWriteMode.IgnoreSchema);
        //To string
        StringBuilder stringBuilder = new StringBuilder();
        dataTable.WriteXml(new StringWriter(stringBuilder));
        Debug.WriteLine(stringBuilder.ToString());
    }
}

这会生成没有任何命名空间的 xml,并将像上面一样创建三行。

【讨论】:

  • 刚试过你的推荐,没有变化。如果您将 typeof(long) 更改为 typeof(object),那应该反映我的设置。
  • 测试了您的 StringBuilder 附录,仍然没有变化。
  • @Avneesh - 你能创建一个小样本并显示输出吗?有时人们有一个很好的答案,可能不适用于 OP,但适用于一般情况。
  • 我已经粘贴了上面的整个程序,它比我认为使用克隆要干净得多。
【解决方案2】:

我想出了一个解决方案,但在我宣布这是答案之前,我会等待更有经验的意见。

正如我在 cmets 中所指出的,命名空间和数据类型声明仅出现在值字段中,因为它在 DataTable 声明中被转换为对象。这有功能价值,所以我不能改变它。但是我可以克隆表,在克隆的数据表仍然为空时更改字段的数据类型,用原始数据表中的数据填充表,然后执行与我最初相同的 WriteXML()。

Public class Parameters
{   private DataTable ParamList = new DataTable();

    public Parameters()
    {   //Default constructor, build datatable with two empty columns
        ParamList.TableName = "Parameter";
        ParamList.Columns.Add("Name",typeof(string));
        ParamList.Columns.Add("Value",typeof(object)); }
    ...
    public string ConvertToXML()
    {   string result;

        //Clone Datatable, change Object field to datatype String
        var dtClone = ParamList.Clone();
        dtClone.Columns["Value"].DataType = typeof(string);
        ParamList.AsEnumerable().CopyToDataTable(dtClone, LoadOption.OverwriteChanges);

        using(var sw = new System.IO.StringWriter())
        {   dtClone.WriteXml(sw);
            result = sw.ToString();
        }
        return result;
    }
}

输出:

<DocumentElement>
  <Parameter>
    <Name>ClientNumber</Name>
    <Value>00001</Value>
  </Parameter>
  <Parameter>
    <Name>FirstName</Name>
    <Value>John</Value>
  </Parameter>
  <Parameter>
    <Name>LastName</Name>
    <Value>Smith</Value>
  </Parameter>
...

【讨论】:

  • 你为什么不直接做 typeof string 而不是再次更改?ParamList.Columns.Add("Value",Type.GetType("System.Object"));
  • 直到今天才知道语法存在!做出改变,谢谢~
【解决方案3】:

您在上面所做的实际上是 Avneesh 建议的(在编辑之前)。

如果你真的想吃苦,那就继承 XmlWriter。它是抽象类。要在序列化中使用它,请执行以下操作:

DataTable dt;

var myXmlSerialization = new MyXmlWriter();

dt.WriteXml(myXmlSerialization);

XmlWriter 实现示例可以在here找到

我建议你不要这样做。

【讨论】:

    【解决方案4】:

    这很简单。如果您有 SomeDataSet,只需将其前缀和命名空间设置为 null:

    SomeDataSet.Prefix = null;
    SomeDataSet.Namespace = null;
    SomeDataSet.Table.WriteXml(filename);
    

    【讨论】:

    • 在我的示例代码中尝试了这个建议:在 DataTable 声明中添加了 Prefix = null 和 Namespace = null。但输出没有变化。
    • 尝试在包含您的表的 DataSet 上执行此操作。我也失败了宽度数据表,但成功使用包含该数据表的数据集
    猜你喜欢
    • 2013-01-10
    • 2011-06-14
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    相关资源
    最近更新 更多