2016-05-06 4 views
0

Я пытаюсь десериализовать XML-документ с разными корневыми пространствами имен в класс C#.Deserialize XML-документ для класса C# с несколькими пространствами имен root (xmlns)

Короче говоря, я десериализации несколько версий подобного XML-документа, например, так:

<IndexRoot Code="0664" xmlns="http://tempuri/2012/1.0"> 
    <Name>Foo</Name> 
    <Color>blue</Color> 
    ... 
</IndexRoot> 


<IndexRoot Code="0678" xmlns="http://tempuri/2012/2.0"> 
    <Name>Bar</Name> 
    <Character>Smurf</Character> 
</IndexRoot> 

Каждая версия, очевидно, может иметь различные элементы под ним, и в то время как большинство элементов одинаковы есть некоторые различия. В приведенном выше примере атрибут Name доступен в каждой версии, а цвет/символ уникален для каждой версии.

В идеале я хочу отнести это к простой функции, которая дает мне отраженный конкретный класс. Как так:

public IndexRoot Get(string fileName) { 
    var doc = XDocument.Load(fileName); 
    return xmlSerializer.Deserialize<IndexRoot>(doc); 
} 

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

[Serializable, XmlRoot(ElementName = "IndexRoot", Namespace = "http://tempuri/2012/2.0")] 
public class IndexRoot 
{ 
    [XmlAttribute("Code")] 
    public string Code { get; set; } 

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

Как вы можете видеть, жёстко namespace будет работать для версий 2.0, но будет сбой для других версий за исключением: «IndexRoot xmlns = 'http://tempuri/2012/1.0' не ожидалось."

Вопрос: Как я могу десериализовать XML на объект C#, принимая во внимание множественные пространства имен?

В идеале это отразилось бы на конкретном типе на версию. Но я даже соглашусь на получение «базового класса» с общими, совместно используемыми свойствами. В любом случае, я в настоящее время застрял с текущим жестко закодированным значением пространства имен в [XmlRoot].

Я пробовал:

  1. Добавление дублируют [XmlRoot] атрибуты (которые не поддерживаются)
  2. Создать базовый класс (BaseIndexRoot), выводя два экземпляра из него и декорирования этих дериватов с [XmlRoot ] атрибут (то же самое «не ожидается» ошибка)
  3. Удаление пространства имен все вместе приводит также к «не ожидается» ошибка

ответ

0

Я смог решить проблему десериализации документов XML с той же структурой, но с разными пространствами имен, со структурой ниже.

Во-первых, я создал производные классы для каждой конкретной версии и украшен тем с пространством имен:

[Serializable, XmlRoot(ElementName = "IndexRoot", Namespace = "http://tempuri/2012/1.0")] 
public class IndexRootV10 : IndexRoot { } 

[Serializable, XmlRoot(ElementName = "IndexRoot", Namespace = "http://tempuri/2012/2.0")] 
public class IndexRootV20 : IndexRoot { } 

public class IndexRoot 
{ 
    [XmlAttribute("Code")] 
    public string Code { get; set; } 

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

Все, что мне нужно сделать после того, как это должно было просто изменить функцию десериализации, чтобы определить, какая версия (dervied класс) применять:

public IndexRoot Get(string fileName) { 
    var doc = XDocument.Load(fileName); 

    switch (doc.Root?.Name.NamespaceName) 
    { 
     case "http://tempuri/2012/1.0": 
      response = xmlSerializer.Deserialize<IndexRootV10>(doc); 
      break; 
     case "http://tempuri/2012/2.0": 
      response = xmlSerializer.Deserialize<IndexRootV20>(doc); 
      break; 
     default: 
      throw new NotSupportedException($"Unsupported xmlns namespace (version): {doc.Root.Name.NamespaceName}"); 
    } 
} 

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

С другой стороны, если конкретная версия имеет разные свойства, производные классы теперь идеально подходят для отражения этого.

0

Я обычно делаю это, как этот

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


namespace ConsoleApplication91 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string xml = 
      "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + 
      "<IndexRoot Code=\"0664\" xmlns=\"http://tempuri/2012/1.0\">" + 
       "<Name>Foo</Name>" + 
       "<Color>blue</Color>" + 
      "</IndexRoot>"; 

      XDocument doc = XDocument.Parse(xml); 
      XElement indexRoot = (XElement)doc.FirstNode; 
      XNamespace ns = indexRoot.Name.Namespace; 

      string name = indexRoot.Element(ns + "Name").Value; 

      XElement indexRoot2 = doc.Descendants().Where(x => x.Name.LocalName == "IndexRoot").FirstOrDefault(); 

     } 


    } 

}