Десериализация XML-файла со смешанными типами - PullRequest
0 голосов
/ 08 февраля 2019

Большое спасибо заранее за любую помощь в создании класса и десериализации XML-файла, как показано ниже в .NET

пример XML-данных

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
    <Article>
        <Story>
            <Title>Some Title 1</Title>
            <Author>John</Author>
            <Lead>Some Lead 1</Lead>
            <Subtitle>SubTitle 1-1</Subtitle>
            <Body>body 1-1-1</Body>
            <Body>body 1-1-2</Body>
            <Body>body 1-1-3</Body>
            <Body>body 1-1-4</Body>
            <Subtitle>SubTitle 1-2</Subtitle>
            <Body>body 1-2-1</Body>
            <Body>body 1-2-2</Body>
            <Subtitle>SubTitle 1-3</Subtitle>
            <Body>body 1-3-1</Body>
            <Body>body 1-3-2</Body>
            <Body>body 1-3-3</Body>
        </Story>
        <Story>
            <Title>Some Title 2</Title>
            <Author>Adam</Author>
            <Lead>Some Lead 2</Lead>
            <Subtitle>SubTitle 2-1</Subtitle>
            <Body>body 2-1-1</Body>
            <Body>body 2-1-2</Body>
            <Body>body 2-1-3</Body>
            <Subtitle>SubTitle 2-2</Subtitle>
            <Body>body 2-2-1</Body>
            <Body>body 2-2-2</Body>
            <Subtitle>SubTitle 2-3</Subtitle>
            <Body>body 2-3-1</Body>
        </Story>
        <Story>
            <Picture>
                <Image href="someFile1.jpg"></Image>
                <Credit>Credit 1</Credit>
                <Description>Description Image 1</Description>
            </Picture>
        </Story>
        <Story>
            <Picture>
                <Image href="someFile2.jpg"></Image>
                <Credit>Credit 2</Credit>
            </Picture>
        </Story>
    </Article>
</Root>

Я подготовил класс домена для этого(но, возможно, это не лучшая идея для моего XML-файла)

using System.Collections.Generic;
using System.Xml.Serialization;

namespace QgeImagingXmlConnector.Domain
{
    [XmlRoot(ElementName = "Root")]
    public class InputXmlModel
    {
        [XmlElement("Article")]
        public List<Article> Articles { get; set; }
    }


    public class Article
    {
        [XmlElement("Story")]
        public List<Story> Stories { get; set; }
    }

    public class Story
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string Lead { get; set; }
        public List<Item> Items { get; set; }
        //OR
        public List<StoryPicture> Pictures { get; set; }
    }

    public class StoryPicture
    {
        public string ImageHref { get; set; }
        public string Credit { get; set; }
        public string Description { get; set; }
    }


    public class Item
    {
        public string ItemType { get; set; } //   Possible: Body or Subtitle
        public string ItemText { get; set; }
    }
}

и метод десериализации

public InputXmlModel GetInputXmlModelByXmlFile(string filePath)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(InputXmlModel));
            TextReader tr = new StreamReader(filePath);
            var result = (InputXmlModel)serializer.Deserialize(tr);
            tr.Close();
            return result;
        }

И мой вопрос: как изменить мой класс для работы (добавивнекоторые атрибуты или изменение структуры)

STORY может, например, Story с некоторым содержимым или Story с одним изображением, поэтому в моем классе я добавил 2 класса Story и StoryPicture. В Content of Story у нас может быть много тегов body или subtitle - нопорядок важен

С уважением

PS

это то, что я хочу получить, в результате я помещаю данные только для первой истории

var result = new InputXmlModel
            {
                Articles = new List<Article>
                {
                    {
                        new Article
                        {
                            Stories = new List<Story>
                            {
                                {new Story
                                    {
                                        Title = "Some Title 1",
                                        Author = "John",
                                        Lead="Some Lead 1",
                                        Items = new List<Item>
                                        {
                                            new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-1"},
                                            new Item{ItemType = "Body", ItemText = "body 1-1-1"},
                                            new Item{ItemType = "Body", ItemText = "body 1-1-2"},
                                            new Item{ItemType = "Body", ItemText = "body 1-1-3"},
                                            new Item{ItemType = "Body", ItemText = "body 1-1-4"},
                                            new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-2"},
                                            new Item{ItemType = "Body", ItemText = "body 1-2-1"},
                                            new Item{ItemType = "Body", ItemText = "body 1-2-2"},
                                            new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-3"},
                                            new Item{ItemType = "Body", ItemText = "body 1-3-1"},
                                            new Item{ItemType = "Body", ItemText = "body 1-3-2"},
                                            new Item{ItemType = "Body", ItemText = "body 1-3-3"},
                                        }
                                    } 
                                }
                                // here next 3 stories ( one with Items, two for pictures )
                            }
                        }
                    }
                }
            };

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

Да, вы можете сделать это тоже так.Класс вашей модели хотел бы:

using System.Collections.Generic;
using System.Xml.Serialization;

namespace QgeImagingXmlConnector.Domain
{
    [XmlRoot(ElementName = "Root")]
    public class InputXmlModel
    {
        [XmlElement("Article")]
        public List<Article> Articles { get; set; }
    }


    public class Article
    {
        [XmlElement("Story")]
        public List<Story> Stories { get; set; }
    }

    public class Story
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string Lead { get; set; }
        [XmlElement("Item")]
        public List<Item> Items { get; set; }
        [XmlElement("Picture")]
        public List<StoryPicture> Pictures { get; set; }
    }

    public class StoryPicture
    {
        public string ImageHref { get; set; }
        public string Credit { get; set; }
        public string Description { get; set; }
    }


    public class Item
    {
        public string ItemType { get; set; } //   Possible: Body or Subtitle
        public string ItemText { get; set; }
    }
}

А ваш XML такой:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
    <Article>
        <Story>
            <Title>Some Title 1</Title>
            <Author>John</Author>
            <Lead>Some Lead 1</Lead>
            <Subtitle>SubTitle 1-1</Subtitle>
            <Body>body 1-1-1</Body>
            <Body>body 1-1-2</Body>
            <Body>body 1-1-3</Body>
            <Body>body 1-1-4</Body>
            <Subtitle>SubTitle 1-2</Subtitle>
            <Body>body 1-2-1</Body>
            <Body>body 1-2-2</Body>
            <Subtitle>SubTitle 1-3</Subtitle>
            <Body>body 1-3-1</Body>
            <Body>body 1-3-2</Body>
            <Body>body 1-3-3</Body>
        </Story>
        <Story>
            <Title>Some Title 2</Title>
            <Author>Adam</Author>
            <Lead>Some Lead 2</Lead>
            <Subtitle>SubTitle 2-1</Subtitle>
            <Body>body 2-1-1</Body>
            <Body>body 2-1-2</Body>
            <Body>body 2-1-3</Body>
            <Subtitle>SubTitle 2-2</Subtitle>
            <Body>body 2-2-1</Body>
            <Body>body 2-2-2</Body>
            <Subtitle>SubTitle 2-3</Subtitle>
            <Body>body 2-3-1</Body>
             <Picture>
                <Image href="someFile1.jpg"></Image>
                <Credit>Credit 1</Credit>
                <Description>Description Image 1</Description>
            </Picture>
            <Picture>
                <Image href="someFile2.jpg"></Image>
                <Credit>Credit 2</Credit>
            </Picture>
        </Story>
    </Article>
</Root>

Это то, что вы ищете?

0 голосов
/ 08 февраля 2019

Попробуйте следующий xml linq:

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


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

            Article article = doc.Descendants("Article").Select(x => new Article() { Stories = x.Elements("Story").Select(y => Story.ParseStory(y)).ToList() }).FirstOrDefault();

        }


    }
    public class InputXmlModel
    {
       public List<Article> Articles { get; set; }

    }


    public class Article
    {
        public List<Story> Stories { get; set; }
    }

    public class Story
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string Lead { get; set; }
        public List<Item> Items { get; set; }
        public List<StoryPicture> Pictures { get; set; }

        enum State
        {
            DEFAULT,
            SUBTITLE,

        }
        public static Story ParseStory(XElement xStory)
        {
            Story story = new Story();
            State state = State.DEFAULT;
            Item newItem = null;
            StoryPicture newPicture = null;
            foreach (XElement child in xStory.Elements())
            {
                switch(state)
                {
                    case State.DEFAULT :
                        switch (child.Name.LocalName)
                        {
                            case "Title" :
                                story.Title = (string)child;
                                break;
                            case "Author":
                                story.Author = (string)child;
                                break;
                            case "Lead":
                                story.Lead = (string)child;
                                break;
                            case "Subtitle":
                                newItem = new Item();
                                if (story.Items == null) story.Items = new List<Item>();
                                story.Items.Add(newItem);

                                state = State.SUBTITLE;
                                break;
                            case "Picture":
                                newPicture = new StoryPicture()
                                {
                                    ImageHref = (string)child.Element("Image").Attribute("href"),
                                    Credit = (string)child.Element("Credit"),
                                    Description = (string)child.Element("Description")
                                };
                                if (story.Pictures == null) story.Pictures = new List<StoryPicture>();
                                story.Pictures.Add(newPicture);

                                break;
                            default:
                                Console.WriteLine("Error");
                                Console.ReadLine();
                                break;
                        }
                        break;


                    case State.SUBTITLE :
                        switch (child.Name.LocalName)
                        {
                            case "Body" :
                                newItem.ItemType = "SubTitle";
                                newItem.ItemText = (string)child;
                                break;

                            case "Subtitle":
                                newItem = new Item();
                                if (story.Items == null) story.Items = new List<Item>();
                                story.Items.Add(newItem);
                                break;

                            default:
                                Console.WriteLine("Error");
                                Console.ReadLine();
                                break;
                        }

                        break;
                }
            }

            return story;
        }
    }

    public class StoryPicture
    {
        public string ImageHref { get; set; }
        public string Credit { get; set; }
        public string Description { get; set; }
    }
    public class Item
    {
        public string ItemType { get; set; } //   Possible: Body or Subtitle
        public string ItemText { get; set; }
    }



}
0 голосов
/ 08 февраля 2019

Если вы удалите тег <Root> в своем XML и измените свой метод десериализации на:

public InputXmlModel GetInputXmlModelByXmlFile(string filePath)
{
    XmlSerializer serializer = new XmlSerializer(typeof(Article));
    using (FileStream fileStream = new FileStream("<PathToFile>", FileMode.Open))
    {
        Article result = (Article)serializer.Deserialize(fileStream);
    }
}

Это должно работать.

...