从 XML 导入 DataSet 后,新行未正确嵌套
After importing DataSet from XML, new rows are not nested properly
我正在使用 DataSet.ReadXml()
将 XML 文件导入新的数据集。然后我将新行添加到数据集中的 table 之一,然后我想再次将该数据集导出到 XML。问题是新行没有正确嵌套,只是附加到 XML 文件的末尾。
程序如下:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
这是输出:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
</ROWDATA>
</DATAPACKET>
<ROW CompanyID="APPL" Description="Apple" />
我想要的是将新行与 table 中的其他行嵌套在一起,如下所示:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
<ROW CompanyID="APPL" Description="Apple" />
</ROWDATA>
</DATAPACKET>
我做错了什么?
我如何从 DataSet.GetXml()
中得到格式正确的 XML ?
ReadXml 将您的 xml 分成许多表。 ReadXml 使用以下嵌套标签执行以下操作 1) DataSet 名称 2) DataTable 名称 3) 行数据:列名是标签,innertext 是值
请参阅下面的代码,它使用 xml linq 解析 xml :
using System;
using System.Data;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
XDocument doc = XDocument.Parse(xml);
DataTable rowTable2 = new DataTable("Table1");
DataRow newRow2 = null;
foreach (XElement field in doc.Descendants("FIELD"))
{
string t = (string)field.Attribute("fieldtype");
Type _type = null;
switch (t)
{
case "string" :
_type = typeof(string);
break;
}
rowTable2.Columns.Add((string)field.Attribute("attrname"), _type);
}
foreach (XElement row in doc.Descendants("ROW"))
{
newRow = rowTable2.Rows.Add();
foreach (XAttribute attribute in row.Attributes())
{
newRow[attribute.Name.LocalName] = (string)attribute;
}
}
newRow = rowTable2.Rows.Add();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
DataSet ds = new DataSet();
ds.Tables.Add(rowTable2);
Console.WriteLine(ds.GetXml());
}
}
}
你从哪里弄来的 XML? DataSet
不支持它的格式。嵌套table时,必须定义table之间的父子关系,并且必须将子table的Nested
属性设置为true
。在您的 XML 中,DataSet
不知道新子行属于哪个父行,因此它将其附加到末尾。
您可以在 MSDN 中阅读有关 Nesting DataRelations 的内容。
话虽如此,您的 XML 实际上并没有父子 table。它有 METADATA
和 ROWDATA
。正如我所说,DataSet
不支持该格式,您必须将元数据移动到 Schema
(XSD)。您可以在 MSDN 中阅读有关 Deriving DataSet Relational Structure from XML Schema.
的内容
这是一个示例,说明您如何使用 XSD 和 XML 表示您的相关数据:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<MyDataSet>
<Companies>
<CompanyID>CC</CompanyID>
<Description>Contoso</Description>
</Companies>
</MyDataSet>
";
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
<xs:schema id=""SomeID""
xmlns=""""
xmlns:xs=""http://www.w3.org/2001/XMLSchema""
xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
<xs:element name=""MyDataSet"" msdata:IsDataSet=""true"">
<xs:complexType>
<xs:choice minOccurs=""0"" maxOccurs=""unbounded"">
<xs:element name=""Companies"">
<xs:complexType >
<xs:sequence>
<xs:element name=""CompanyID"" type=""xs:string"" minOccurs=""0"" />
<xs:element name=""Description"" type=""xs:string"" minOccurs=""0"" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
";
DataSet dataSet = new DataSet();
StringReader sr = new StringReader(xsd);
dataSet.ReadXmlSchema(sr);
sr = new StringReader(xml);
dataSet.ReadXml(sr, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["Companies"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
在这种情况下,您实际上并不需要架构,因为您只有一个 table,所有列都为 string
。因此,如果您从上面的代码中删除架构并再次 运行 它,您将获得完全相同的结果。但是,这让您了解如何使用模式定义 DataSet
结构,因此您可以添加更复杂的 table 以及它们之间的关系。对于没有关系的简单 table,您不需要架构。
我解决了我自己的问题。问题是我不知道 table 之间自动生成的关系创建了需要填充的外键列。
对于 ROW
table,自动生成的外键是 ROWDATA_Id
.
这是按预期工作的更新代码:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
newRow["ROWDATA_Id"] = 0; //This is what I was missing. This nests the row properly
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
另一种解决方案是将外键列 ROWDATA_Id
的 DataColumn.DefaultValue
设置为 0
var rowTable = dataSet.Tables["ROW"];
rowTable.Columns["ROWDATA_Id"].DefaultValue = 0;
这是两种解决方案的输出:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
<ROW CompanyID="APPL" Description="Apple" />
</ROWDATA>
</DATAPACKET>
我正在使用 DataSet.ReadXml()
将 XML 文件导入新的数据集。然后我将新行添加到数据集中的 table 之一,然后我想再次将该数据集导出到 XML。问题是新行没有正确嵌套,只是附加到 XML 文件的末尾。
程序如下:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
这是输出:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
</ROWDATA>
</DATAPACKET>
<ROW CompanyID="APPL" Description="Apple" />
我想要的是将新行与 table 中的其他行嵌套在一起,如下所示:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
<ROW CompanyID="APPL" Description="Apple" />
</ROWDATA>
</DATAPACKET>
我做错了什么?
我如何从 DataSet.GetXml()
中得到格式正确的 XML ?
ReadXml 将您的 xml 分成许多表。 ReadXml 使用以下嵌套标签执行以下操作 1) DataSet 名称 2) DataTable 名称 3) 行数据:列名是标签,innertext 是值
请参阅下面的代码,它使用 xml linq 解析 xml :
using System;
using System.Data;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
XDocument doc = XDocument.Parse(xml);
DataTable rowTable2 = new DataTable("Table1");
DataRow newRow2 = null;
foreach (XElement field in doc.Descendants("FIELD"))
{
string t = (string)field.Attribute("fieldtype");
Type _type = null;
switch (t)
{
case "string" :
_type = typeof(string);
break;
}
rowTable2.Columns.Add((string)field.Attribute("attrname"), _type);
}
foreach (XElement row in doc.Descendants("ROW"))
{
newRow = rowTable2.Rows.Add();
foreach (XAttribute attribute in row.Attributes())
{
newRow[attribute.Name.LocalName] = (string)attribute;
}
}
newRow = rowTable2.Rows.Add();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
DataSet ds = new DataSet();
ds.Tables.Add(rowTable2);
Console.WriteLine(ds.GetXml());
}
}
}
你从哪里弄来的 XML? DataSet
不支持它的格式。嵌套table时,必须定义table之间的父子关系,并且必须将子table的Nested
属性设置为true
。在您的 XML 中,DataSet
不知道新子行属于哪个父行,因此它将其附加到末尾。
您可以在 MSDN 中阅读有关 Nesting DataRelations 的内容。
话虽如此,您的 XML 实际上并没有父子 table。它有 METADATA
和 ROWDATA
。正如我所说,DataSet
不支持该格式,您必须将元数据移动到 Schema
(XSD)。您可以在 MSDN 中阅读有关 Deriving DataSet Relational Structure from XML Schema.
这是一个示例,说明您如何使用 XSD 和 XML 表示您的相关数据:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<MyDataSet>
<Companies>
<CompanyID>CC</CompanyID>
<Description>Contoso</Description>
</Companies>
</MyDataSet>
";
string xsd = @"<?xml version=""1.0"" encoding=""utf-8""?>
<xs:schema id=""SomeID""
xmlns=""""
xmlns:xs=""http://www.w3.org/2001/XMLSchema""
xmlns:msdata=""urn:schemas-microsoft-com:xml-msdata"">
<xs:element name=""MyDataSet"" msdata:IsDataSet=""true"">
<xs:complexType>
<xs:choice minOccurs=""0"" maxOccurs=""unbounded"">
<xs:element name=""Companies"">
<xs:complexType >
<xs:sequence>
<xs:element name=""CompanyID"" type=""xs:string"" minOccurs=""0"" />
<xs:element name=""Description"" type=""xs:string"" minOccurs=""0"" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
";
DataSet dataSet = new DataSet();
StringReader sr = new StringReader(xsd);
dataSet.ReadXmlSchema(sr);
sr = new StringReader(xml);
dataSet.ReadXml(sr, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["Companies"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
在这种情况下,您实际上并不需要架构,因为您只有一个 table,所有列都为 string
。因此,如果您从上面的代码中删除架构并再次 运行 它,您将获得完全相同的结果。但是,这让您了解如何使用模式定义 DataSet
结构,因此您可以添加更复杂的 table 以及它们之间的关系。对于没有关系的简单 table,您不需要架构。
我解决了我自己的问题。问题是我不知道 table 之间自动生成的关系创建了需要填充的外键列。
对于 ROW
table,自动生成的外键是 ROWDATA_Id
.
这是按预期工作的更新代码:
using System;
using System.Data;
using System.IO;
using System.Xml;
public class Program
{
public static void Main()
{
string xml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<DATAPACKET Version=""2.0"">
<METADATA>
<FIELDS>
<FIELD attrname=""CompanyID"" fieldtype=""string"" WIDTH=""10""/>
<FIELD attrname=""Description"" fieldtype=""string"" WIDTH=""40""/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW CompanyID=""CC"" Description=""Contoso""/>
</ROWDATA>
</DATAPACKET>
";
XmlReader reader = XmlReader.Create(new StringReader(xml));
DataSet dataSet = new DataSet();
dataSet.ReadXml(reader, XmlReadMode.InferTypedSchema);
var rowTable = dataSet.Tables["ROW"];
var newRow = rowTable.NewRow();
newRow["CompanyID"] = "APPL";
newRow["Description"] = "Apple";
newRow["ROWDATA_Id"] = 0; //This is what I was missing. This nests the row properly
rowTable.Rows.Add(newRow);
Console.WriteLine(dataSet.GetXml());
}
}
另一种解决方案是将外键列 ROWDATA_Id
DataColumn.DefaultValue
设置为 0
var rowTable = dataSet.Tables["ROW"];
rowTable.Columns["ROWDATA_Id"].DefaultValue = 0;
这是两种解决方案的输出:
<DATAPACKET Version="2.0">
<METADATA>
<PARAMS />
<FIELDS>
<FIELD attrname="CompanyID" fieldtype="string" WIDTH="10" />
<FIELD attrname="Description" fieldtype="string" WIDTH="40" />
</FIELDS>
</METADATA>
<ROWDATA>
<ROW CompanyID="CC" Description="Contoso" />
<ROW CompanyID="APPL" Description="Apple" />
</ROWDATA>
</DATAPACKET>