После импорта DataSet из XML новые строки не будут правильно вложены - PullRequest
1 голос
/ 19 сентября 2019

Я использую DataSet.ReadXml() для импорта файла XML в новый набор данных.Затем я добавляю новую строку в одну из таблиц внутри DataSet, а затем хочу снова экспортировать этот DataSet в 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" />

Я хочу, чтобы новая строка была вложена в другие строки из этой таблицы следующим образом:

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

Что я делаю неправильно?Как мне получить правильно сформированный XML из DataSet.GetXml()?

Вот программа, запущенная в dotnetfiddle

Ответы [ 3 ]

0 голосов
/ 19 сентября 2019

Откуда вы взяли этот XML?Он отформатирован способом, не поддерживаемым DataSet.При вложении таблиц вы должны определить родительско-дочерние отношения между таблицами и установить для свойства Nested дочерней таблицы значение true.В вашем XML DataSet не знает, к какому родительскому элементу принадлежит новая дочерняя строка, поэтому он добавляет его в конец.

В MSDN вы можете прочитать о Вложении DataRelations .

Сказав это, ваш XML на самом деле не имеет родительских и дочерних таблиц.Он имеет METADATA и ROWDATA.Как я уже сказал, этот формат не поддерживается DataSet, вам придется переместить ваши метаданные в Schema (XSD).В MSDN вы можете прочитать о Извлечение реляционной структуры DataSet из XML-схемы .

Вот пример того, как вы представляете свои данные с помощью 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());
    }
}

В этом случае вам на самом деле не нужна схема, потому что у вас есть только одна таблица со всеми столбцами как string.Поэтому, если вы удалите схему из приведенного выше кода и запустите ее снова, вы получите точно такие же результаты.Тем не менее, это дает вам представление о том, как определить структуру DataSet с использованием схемы, чтобы вы могли добавлять более сложные таблицы со связями между ними.Для простых таблиц без связей вам не нужна схема.

0 голосов
/ 19 сентября 2019

Я решил свой вопрос.Проблема заключалась в том, что я не знал, что автоматически генерируемые связи между таблицами создают столбцы внешнего ключа, которые необходимо заполнить.Для таблицы ROW автоматически сгенерированный внешний ключ равен 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());
    }
}

Альтернативное решение - установить *От 1008 * до 0 для столбца внешнего ключа ROWDATA_Id

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>

Вот первое решение, работающее наdotnetfiddle

Вот альтернативное решение, работающее на dotnetfiddle

0 голосов
/ 19 сентября 2019

ReadXml разбивает ваш xml на множество таблиц.ReadXml выполняет следующие со следующими вложенными тегами 1) Имя набора данных 2) Имя таблицы данных 3) Данные строки: имя столбца является тегом, а внутренний текст - значением

См. Мой код ниже, который анализирует XML с xml linq:

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());
        }
    }
}
...