Десериализация XML с использованием xml-элемента / атрибутов

#c# #.net #xml #xml-serialization

#c# #.net #xml #xml-сериализация

Вопрос:

Нужна ваша помощь в настройке атрибутов XML для десериализации XML.

Это мой входной xml:

 <form>
<question id="QnA">
<answer>AnswerforA</answer>
</question>
<question id="QnB">
<answer>AnswerforB</answer>
</question>
<question id="QnC">
<answer>AnswerforC</answer>
</question>
</form>
  

Идентификаторы каждого тега элемента вопроса соответствуют свойству класса, а его значение является внутренним текстом соответствующего элемента ответа.

Файл .cs будет выглядеть следующим образом

  public class Test
{

   private string qnaAns;    
   private string qnbAns;   
   private string qncAns;   

    public string QnA
    {
    get{ return qnaAns;}
    set{qnaAns = value;}
    }

    public string QnB
    {
    get{ return qnbAns;}
    set{qnbAns = value;}
    }

    public string QnC
    {
    get{ return qncAns;}
    set{qncAns = value;}
    }
}
  

и я использую следующий код для десериализации

 XmlSerializer ser = new XmlSerializer(typeof(Test));

XmlReader xr = new xmlReader(inputxml);

Test t = ser.Deserialize(xr) as Test;
  

Пожалуйста, дайте мне знать, как установить XML-элемент / атрибут для тестового класса, чтобы достичь этого.

Спасибо за ваше время.

Комментарии:

1. Мне немного лень просматривать ваш код и выяснять, с чем у вас возникли проблемы, поэтому, пожалуйста, сообщите нам, в чем ваша проблема.

2. Вы должны либо структурировать свой DTO для представления данных, которые вы пытаетесь сериализовать, либо вам придется реализовать IXmlSerializable (не весело). Смотрите ответ Мэтта для примера первого (и правильного, IMO) варианта.

Ответ №1:

  [XmlRoot("form")]
    public class Form
    {
        [XmlElement("question")]
        public List<Question> Questions { get; set; }

        public Form()
        {
            Questions = new List<Question>();
        }
    }
    public struct Question
    {
        [XmlAttribute("id")]
        public string ID { get; set; }

        [XmlElement("answer")]
        public string Answer { get; set; }
    }
  

Затем для сериализации я использую следующие расширения:

 public static bool XmlSerialize<T>(this T item, string fileName) 
        { 
            return item.XmlSerialize(fileName, true); 
        } 
        public static bool XmlSerialize<T>(this T item, string fileName, bool removeNamespaces) 
        { 
            object locker = new object(); 

            XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces(); 
            xmlns.Add(string.Empty, string.Empty); 

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 

            XmlWriterSettings settings = new XmlWriterSettings(); 
            settings.Indent = true; 
            settings.OmitXmlDeclaration = true; 

            lock (locker) 
            { 
                using (XmlWriter writer = XmlWriter.Create(fileName, settings)) 
                { 
                    if (removeNamespaces) 
                    { 
                        xmlSerializer.Serialize(writer, item, xmlns); 
                    } 
                    else { xmlSerializer.Serialize(writer, item); } 

                    writer.Close(); 
                } 
            } 

            return true; 
        } 
        public static T XmlDeserialize<T>(this string s) 
        { 
            object locker = new object(); 
            StringReader stringReader = new StringReader(s); 
            XmlTextReader reader = new XmlTextReader(stringReader); 
            try 
            { 
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 
                lock (locker) 
                { 
                    T item = (T)xmlSerializer.Deserialize(reader); 
                    reader.Close(); 
                    return item; 
                } 
            } 
            finally 
            { 
                if (reader != null) 
                { reader.Close(); } 
            } 
        } 
        public static T XmlDeserialize<T>(this FileInfo fileInfo) 
        { 
            string xml = string.Empty; 
            using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read)) 
            { 
                using (StreamReader sr = new StreamReader(fs)) 
                { 
                    return sr.ReadToEnd().XmlDeserialize<T>(); 
                } 
            } 
        } 
  

Надеюсь, это поможет.

PS — Расширения взяты из моей библиотеки в codeproject:http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Комментарии:

1. Вы можете десериализовать следующим образом: Form form = new FileInfo("c:\test.xml").XmlDeserialize<Form>();

2. не уверен, что методы расширения действительно того стоят, но общий подход (имеющий модель DTO, которая отражает xml) является абсолютно правильным.

3. Спасибо за ваш ответ. Но я не собираюсь иметь список<Вопрос> с двумя элементами внутри. Основываясь на вашем коде, я должен установить свойство QnA как общедоступную строку QnA { get { return Questions[Вопросы. findIndex(t => t.ID ==»QnA»)].Answer; } set { ; } } .. Возможно ли установить свойства напрямую? Спасибо.

4. Кроме Того, возможно ли указать другой параметр «section» наряду с «вопросом» для объекта вопроса, т.Е. Форма также может быть <form> <question id=»QnA»> <answer>AnswerforA</answer> </question> <section id=»QnB»> <answer>AnswerforB</answer> </section> </form>