Десериализовать XML в структуру объекта, включая словарь - PullRequest
0 голосов
/ 17 сентября 2018

Я пытаюсь десериализовать данный XML-файл в структуру объекта.

Это XML:

<StaticData>
  <Configuration>
    <SqlCmdParameters />
    <Tables>
      <Table Schema="dbo" Name="table1">
        <Columns>
          <Column Name="tab1col1" IsPrimaryKey="false" />
          <Column Name="tab1col2" IsPrimaryKey="false" />
        </Columns>
      </Table>
      <Table Schema="dbo" Name="table2">
        <Columns>
          <Column Name="tab2col1" IsPrimaryKey="false" />
          <Column Name="tab2col2" IsPrimaryKey="false" />
        </Columns>
      </Table>
    </Tables>
  </Configuration>
  <TableDataItems>
    <TableData Schema="dbo" Name="table1">
      <RowData tab1col1="11" tab1col2="text1" tab1col3="anotherText1" />
      <RowData tab1col1="12" tab1col2="text2" tab1col3="anotherText2"/>
      <RowData tab1col1="13" tab1col2="text3" tab1col3="anotherText3"/>

    </TableData>
    <TableData Schema="dbo" Name="table2">
      <RowData tab2col1="22" tab2col2="text1" />
      <RowData tab2col1="23" tab2col2="text1" />
      <RowData tab2col1="24" tab2col2="text1" />
    </TableData>
  </TableDataItems>
</StaticData>

Классы, которые я хочу заполнить:

    [XmlRoot("StaticData")]
public class StaticData
{
    [XmlElement("Configuration")]
    public Configuration Configuration { get; set; }

    [XmlElement("TableDataItems")]
    public TableDataItems TableDataItems { get; set; }
}

public class Configuration
{
    [XmlElement("Tables")]
    public List<Table> Tables { get; set; }

    [XmlElement("SqlCmdParameters")]
    public List<SqlCommandParameter> SqlCommandParameters { get; set; }
}

public class TableDataItems
{
    [XmlElement("TableData")]
    public List<Table> TableDatas { get; set; }
}

public class Table
{
    [XmlAttribute("Name")]
    public string TableName { get; set; }

    [XmlAttribute("Schema")]
    public string SchemaName { get; set; }

    [XmlElement("Columns")]
    public List<Column> Columns { get; set; }

    [XmlElement("RowData")]
    public List<Row> Rows { get; set; }

    public Table()
    {
        Columns = new List<Column>();
        Rows = new List<Row>();
    }
}

public class Column
{
    [XmlAttribute("Name")]
    public string Name { get; set; }

    [XmlAttribute("IsPrimaryKey")]
    public bool IsPrimaryKey { get; set; }
}

public class Row
{
    public Row()
    { 
        RowData = new Dictionary<string, string>();
    }
    ???What Attribute should I put here???
    public Dictionary<string, string> RowData { get; set; }
}

Итак, все работает нормально, пока я не доберусь до места, где все атрибуты должны быть заполнены в словарь.

Вот как я до сих пор десериализирую XML:

public void CreateObjectStructureFromXml()
    {
        using (TextReader textReader = new StringReader(XmlDocument.ToString()))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(StaticData));
            StaticData = (StaticData) serializer.Deserialize(textReader);
        }
    }

Я получаю исключение, как только доберусь до элементов Row.

Может кто-нибудь указать мне, где я допустил ошибку или что мне следует делать? XML RowData может поставляться с переменным количеством атрибутов. Атрибуты являются содержимым таблицы базы данных.

Заранее большое спасибо

1 Ответ

0 голосов
/ 18 сентября 2018

Попробуйте xml linq:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Table.tables = doc.Descendants("Table").Select(x => new Table() {
                SchemaName = (string)x.Attribute("Schema"),
                TableName = (string)x.Attribute("Name"),
                Columns = x.Descendants("Column").Select(y => new Column()
{
                    Name = (string)y.Attribute("Name"),
                    IsPrimaryKey = (Boolean)y.Attribute("IsPrimaryKey")
                }).ToList()
            }).ToList();

            Dictionary<string, XElement> tableData = doc.Descendants("TableData")
                .GroupBy(x => (string)x.Attribute("Name"), y => y)
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            foreach(Table table in Table.tables)
            {
                XElement xTable = tableData[table.TableName];
                table.SchemaName = (string)xTable.Attribute("Schema");
                table.Rows = xTable.Elements("RowData").Select(x => new Row() {
                    RowData = x.Attributes()
                    .GroupBy(y => y.Name.LocalName, z => (string)z)
                    .ToDictionary(y => y.Key, z => z.FirstOrDefault())
                }).ToList();
            }

        }
    }
    public class Table
    {
        public static List<Table> tables = new List<Table>();
        public string TableName { get; set; }

        public string SchemaName { get; set; }

        public List<Column> Columns { get; set; }

        public List<Row> Rows { get; set; }

        public Table()
        {
            Columns = new List<Column>();
            Rows = new List<Row>();
        }
    }
    public class Column
    {
        public string Name { get; set; }

        public bool IsPrimaryKey { get; set; }
    }

    public class Row
    {
        public Dictionary<string, string> RowData { get; set; }
    }
}
...