Сериализация сложного содержимого строки XML - PullRequest
1 голос
/ 11 декабря 2019

Я пытаюсь сериализовать содержимое XML в объект. Я использую .Net 4.6.1. XML, который я пытаюсь сериализовать:

<THEROOT>
  <ITEM>
    <TITLE>
      This is my title
    </TITLE>
    <DESCRIPTION>
      <P>Line 1 of the description</P>
      <P>Line 2 of the description</P>
      <P>Final line of description</P>
    </DESCRIPTION>
    <MOREINFO>
      <P>Some additional stuff here</P>
      <P>And another line</P>
      <P>And final line</P>
    </MOREINFO>
  </ITEM>
  <ITEM>
    <TITLE>
      Another object is here
    </TITLE>
    <DESCRIPTION>
      <P>Some description</P>
      <P>That I need to parse</P>
      <P>Into a string</P>
    </DESCRIPTION>
    <MOREINFO>
      <P>More info lines</P>
      <P>Would go here</P>
    </MOREINFO>
  </ITEM>
</THEROOT>

И вот объект, к которому я пытаюсь сериализоваться:

public class TestModel
{
    [XmlRoot(ElementName = "THEROOT")]
    public class TheRoot
    {
        [XmlElement(ElementName = "ITEM")]
        public List<Item> Item { get; set; }
    }

    [XmlRoot(ElementName = "ITEM")]
    public class Item
    {
        [XmlElement(ElementName = "TITLE")]
        public string Title { get; set; }

        [XmlElement(ElementName = "DESCRIPTION")]
        public string Description { get; set; }

        [XmlElement(ElementName = "MOREINFO")]
        public string MoreInfo { get; set; }
    }
}

И для полноты, это мой код сериализации (предполагая, что содержимое XML выше является строкой) ..

TestModel.TheRoot rootObject;
using (TextReader tr = new StringReader(myXML))
{
    using (XmlTextReader xr = new XmlTextReader(tr))
    {
        xr.Namespaces = false;
        XmlSerializer serializer = new XmlSerializer(typeof(TestModel.TheRoot));
        rootObject = (TestModel.TheRoot)serializer.Deserialize(xr);
    }
}

В его текущем состоянии я получаю сообщение об ошибке «Метод ReadElementString можно вызывать только для элементов с простым или пустым содержимым». Я понимаю, что это потому, что у меня есть html-теги в моём описании, которые десериализованы как сложные объекты.

Я обнаружил, что «могу» изменить модель так, чтобы она была такой ...

public class TestModel
{
    [XmlRoot(ElementName = "THEROOT")]
    public class TheRoot
    {
        [XmlElement(ElementName = "ITEM")]
        public List<Item> Item { get; set; }
    }

    [XmlRoot(ElementName = "ITEM")]
    public class Item
    {
        [XmlElement(ElementName = "TITLE")]
        public string Title { get; set; }

        [XmlElement(ElementName = "DESCRIPTION")]
        public Description Description { get; set; }

        [XmlElement(ElementName = "MOREINFO")]
        public MoreInfo MoreInfo { get; set; }
    }

    [XmlRoot(ElementName = "DESCRIPTION")]
    public class Description
    {
        [XmlElement(ElementName = "P")]
        public P[] P { get; set; }
    }

    [XmlRoot(ElementName = "MOREINFO")]
    public class MoreInfo
    {
        [XmlElement(ElementName = "P")]
        public P[] P { get; set; }
    }

    [XmlRoot(ElementName = "P")]
    public class P
    {
        [XmlText]
        public string Text { get; set; }
    }
}

И это работает в некоторой степени - но это обременительно, когда я знаю, что просто хочу рассматривать весь контент как строку. Предполагая, что я не могу изменить формат XML, есть ли способ, которым я могу получить оба узла Description и MoreInfo для каждой десериализации в один строковый объект?

Я видел различные постыздесь и на других сайтах, но ни один из них не работает безупречно.

1 Ответ

1 голос
/ 11 декабря 2019

Используйте XML LINQ:

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


namespace ConsoleApplication9
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            TestModel model = new TestModel(FILENAME);
        }
    }
    public class TestModel
    {
        public List<Item> items { get; set; }
        public TestModel(string filename)
        {
            XDocument doc = XDocument.Load(filename);

            items = doc.Descendants("ITEM").Select(x => new Item()
            {
                Title = ((string)x.Element("TITLE")).Trim(),
                Description = string.Join(",", x.Element("DESCRIPTION")
                   .Elements("P").Select(y => (string)y)),
                MoreInfo = string.Join(",", x.Element("MOREINFO")
                   .Elements("P").Select(y => (string)y))
            }).ToList();
        }


    }
    public class Item
    {
        public string Title { get; set; }

        public string Description { get; set; }

        public string MoreInfo { get; set; }
    }
}

Используйте следующее с вашим решением, чтобы сгладить результаты

            private string _Description { get; set; }
            [XmlElement(ElementName = "DESCRIPTION")]
            public Description Description
            {
                get { return new Description() { P = _Description.Split(new char[] { ',' }).Select(x => new P() { Text = x}).ToArray() }; }
                set
                {
                    _Description = string.Join(",",value.P.Select(x => x.Text));
                }
            }

            private string _MoreInfo { get; set; }
            [XmlElement(ElementName = "MOREINFO")]
            public MoreInfo MoreInfo
            {
                get { return new MoreInfo() { P = _MoreInfo.Split(new char[] { ',' }).Select(x => new P() { Text = x }).ToArray() }; }
                set
                {
                    _MoreInfo = string.Join(",", value.P.Select(x => x.Text));
                }
            }
...