Десериализуйте вложенный в себя XML-узел

#c# #xml

Вопрос:

У меня есть xml из ответа soap, который выглядит следующим образом (формат которого я не контролирую), обратите внимание на вложенные Campaigns.Campaign.Campaign

 <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
      // ...
   </s:Header>
   <s:Body>
      <SomeResponse xmlns="...">
         <SomeCampaignsResult xmlns:b="..." xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <b:Campaigns>
               <b:Campaign>
                  <b:Campaign>
                     <b:CampaignId>dfdf-dfe-fdf</b:CampaignId>
                     <b:CampaignName>Some name</b:CampaignName>
                  </b:Campaign>
               </b:Campaign>
               <b:CampaignCount>1</b:CampaignCount>
            </b:Campaigns>
         </SomeCampaignsResult>
      </SomeResponse>
   </s:Body>
</s:Envelope>
 

У меня есть следующие занятия:

 namespace Models
{
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "...")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "...", IsNullable = false)]
    public class Campaigns
    {
        public int CampaignCount { get; set; }
        public Campaign Campaign { get; set; }
    }
}


namespace Models
{
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "...")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "...", IsNullable = false)]
    public class Campaign
    {
        public string CampaignId { get; set; }
        public string Name { get; set; }
    }
}
 

Я пытаюсь десериализовать данный xml с помощью этого кода

     XmlDocument SOAPResponse = new XmlDocument();
    SOAPResponse.Load("C:\campaign.xml");

    XmlNamespaceManager nsmgr = new XmlNamespaceManager(SOAPResponse.NameTable);
    nsmgr.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
    nsmgr.AddNamespace("a", "http://www.w3.org/2005/08/addressing");
    nsmgr.AddNamespace("b", "...");
    nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");

    XmlNode justNodes1 = SOAPResponse.SelectSingleNode("//s:Envelope/s:Body", nsmgr);
    XmlNode nodeCampaigns = justNodes1.SelectSingleNode(".//b:Campaigns", nsmgr);
    Campaigns responseCampaigns = null;
    XmlSerializer serializerCampaigns = new XmlSerializer(typeof(Campaigns));
    using (XmlReader reader = new XmlNodeReader(nodeCampaigns))
    {
       responseCampaigns = (Campaigns)serializerCampaigns.Deserialize(reader);
    }
 

И это значение responseCampaigns в конце:

введите описание изображения здесь

Проблема

responseCampaigns.CampaignCount правильно проанализирован/установлен responseCampaigns.Campaign.CampaignId и responseCampaigns.Campaign.Name оба являются нулевыми, так как я неправильно учитываю Campaigns.Campaign.Campaign вложенность

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

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

1. Изменение модели-это единственный вариант, который у вас есть? Вы можете удалить один узел кампании. Чтобы кампании могли иметь узлы для кампании, в которой используется ваша модель кампании.

2. @DhavalR К сожалению, я не контролирую входящий XML-файл или формат. Я открыт для другого подхода, если мне нужно извлечь кампании. Кампания. Однако кампания ведется по-другому.

3. У вас может быть свойство в классе Campaign, которое возвращает объект самой кампании. Сделайте этот класс одноэлементным. Надеюсь, это сработает для вас.

Ответ №1:

У вас есть два разных пространства имен»…», что создает проблему. Попробуйте код ниже :

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

namespace ConsoleApplication183
{
    class Program
    {
        const string FILENAME = @"c:temptest.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
            Envelope envelope = (Envelope)serializer.Deserialize(reader);

        }
    }
    [XmlRoot(Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class Envelope
    {
        [XmlElement(Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        public Body Body { get; set; }
    }
    public class Body
    {
        [XmlArray(ElementName = "SomeResponse", Namespace = "empty")]
        [XmlArrayItem(ElementName = "SomeCampaignsResult", Namespace = "empty")]
        public List<CampaignsResult> CampaignsResult { get; set; }
    }
    public class CampaignsResult
    {
        [XmlArray(ElementName = "Campaigns", Namespace = "bspace")]
        [XmlArrayItem(ElementName = "Campaign", Namespace = "bspace")]
        public List<Campaigns> Campaigns { get; set; }
    }
    public class Campaigns
    {
        [XmlElement(Namespace = "bspace")]
        public Campaign Campaign { get; set; }
    }
    public class Campaign
    {
        public string CampaignId { get;set;}
        public string CampaignName { get; set; }
    }

 
}
 

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

1. Спасибо за вашу помощь jdweng, я пытался реализовать это таким образом, но столкнулся с некоторыми проблемами с неожиданными элементами в xml (конечно, это моя вина). Экспериментируя с тем, что я узнал из вашего подхода, я заставил его работать, изменив свою модель кампаний, чтобы указать XmlArrayItem и XmlArray как с кампанией имени элемента, так и с изменением участника кампании на список

Ответ №2:

Изменение модели моих кампаний для указания XmlArrayItem и XmlArray как в кампании с именем элемента, так и в изменении участника кампании на Список решило эту проблему для меня.

 namespace Models
{
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "...")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "...", IsNullable = false)]
    public class Campaigns
    {
        public int CampaignCount { get; set; }

        [XmlArrayItem(ElementName = "Campaign")]
        [XmlArray(ElementName = "Campaign")]
        public List<Campaign>  Campaign { get; set; }
    }
}