Десериализация XML без пространств имен, но в классе, ожидающем пространства имен




Дубликат:
пропуск всех пространств имен xml при сериализации объекта?
Не тот же.. Я хочу по-другому: Десериализоваться!






У меня есть класс C#, как показано ниже:



[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.portalfiscal.inf.br/nfe")]
[System.Xml.Serialization.XmlRootAttribute("NFe", Namespace = "http://www.portalfiscal.inf.br/nfe", IsNullable = false)]
public partial class TNFe
{

private TNFeInfNFe infNFeField;

private SignatureType signatureField;

/// <remarks/>
public TNFeInfNFe infNFe
{ ...


Я использую этот класс для сериализации / десериализации XML-файлов по запросу пользователя.
Но у меня есть проблема: определение пространств имен было добавлено в новую версию этого программного обеспечения.
XML остается тем же самым, только добавляя определение пространств имен.



Напр., последний версия...



<?xml version="1.0" encoding="utf-8" ?>
<NFe>
<infNFe version="1.10">
...


И новая версия...



<?xml version="1.0" encoding="utf-8" ?> 
<NFe xmlns="http://www.portalfiscal.inf.br/nfe">
<infNFe version="2.10">
...


Мне нужно загрузить XML-файлы с этими пространствами имен и без них.
У меня есть много вложенных классов, и каждый из них имеет свое собственное определение пространств имен.



Я хотел бы использовать одни и те же классы для обоих XML, с пространствами имен и без них.



Я попытался создать XmlTextReader и перезаписать метод NamespaceURI, но по-прежнему получаю исключение без большой информации. Я думаю, что .NET engine пытается заставить класс определение пространства имен по отношению к XML.

568   4  

4 ответов:

Я столкнулся с подобной проблемой с прокси-классом. По причинам, которые я не буду вдаваться в подробности, мне нужно было сериализовать класс вручную с помощью XmlSerializer на веб-сервере и десериализовать на клиенте. Мне не удалось найти элегантное решение в интернете, поэтому я просто избежал этой проблемы, удалив атрибут XmlTypeAttribute из прокси-класса вручную после его автоматического создания в Visual Studio.

Я все время возвращался, чтобы посмотреть, есть ли способ заставить пространство имен тренироваться. Вот как я его получил Работа без необходимости изменять автоматически генерируемые классы. В итоге я использовал XmlTextReader, чтобы возвращать нужное пространство имен на узлах, соответствующих имени свойства. Есть место для улучшения, но я надеюсь, что это кому-то поможет.

class Program
{
    static void Main(string[] args)
    {
        //create list to serialize
        Person personA = new Person() { Name = "Bob", Age = 10, StartDate = DateTime.Parse("1/1/1960"), Money = 123456m };
        List<Person> listA = new List<Person>();
        for (int i = 0; i < 10; i++)
        {
            listA.Add(personA);
        }

        //serialize list to file
        XmlSerializer serializer = new XmlSerializer(typeof(List<Person>));
        XmlTextWriter writer = new XmlTextWriter("Test.xml", Encoding.UTF8);
        serializer.Serialize(writer, listA);
        writer.Close();

        //deserialize list from file
        serializer = new XmlSerializer(typeof(List<ProxysNamespace.Person>));
        List<ProxysNamespace.Person> listB;
        using (FileStream file = new FileStream("Test.xml", FileMode.Open))
        {
            //configure proxy reader
            XmlSoapProxyReader reader = new XmlSoapProxyReader(file);
            reader.ProxyNamespace = "http://myappns.com/";      //the namespace of the XmlTypeAttribute 
            reader.ProxyType = typeof(ProxysNamespace.Person); //the type with the XmlTypeAttribute

            //deserialize
            listB = (List<ProxysNamespace.Person>)serializer.Deserialize(reader);
        }

        //display list
        foreach (ProxysNamespace.Person p in listB)
        {
            Console.WriteLine(p.ToString());
        }

        Console.ReadLine();
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime StartDate { get; set; }
    public decimal Money { get; set; }
}

namespace ProxysNamespace
{
    [XmlTypeAttribute(Namespace = "http://myappns.com/")]
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime Birthday { get; set; }
        public decimal Money { get; set; }

        public override string ToString()
        {
            return string.Format("{0}:{1},{2:d}:{3:c2}", Name, Age, Birthday, Money);
        }
    }
}

public class XmlSoapProxyReader : XmlTextReader
{
    List<object> propNames;
    public XmlSoapProxyReader(Stream input)
        : base(input)
    {
        propNames = new List<object>();
    }

    public string ProxyNamespace { get; set; }

    private Type proxyType;
    public Type ProxyType
    {
        get { return proxyType; }
        set
        {
            proxyType = value;
            PropertyInfo[] properties = proxyType.GetProperties();
            foreach (PropertyInfo p in properties)
            {
                propNames.Add(p.Name);
            }
        }
    }

    public override string NamespaceURI
    {
        get
        {
            object localname = LocalName;
            if (propNames.Contains(localname))
                return ProxyNamespace;
            else
                return string.Empty;
        }
    }
}

Для десериализации XML без пространства имен добавьте атрибут XmlRoot в класс, представляющий вершину иерархии:

[XmlRoot(ElementName="plugins", Namespace="")]

В моем примере Xml не имеет пространства имен и начинается как

<plugins><...

Класс, в который он десериализуется:

[XmlRoot(ElementName="plugins", Namespace="")]
public class Plugins
{
   //...
}

Очевидно, что ваша ситуация может быть немного другой, но этот код работает для меня:

using (FileStream stream = File.Open(filePath, FileMode.Open))
{
   XmlReader reader = new XmlTextReader(stream);                
   XmlSerializer serializer = new XmlSerializer(typeof(Plugins));
   var plugins = (Plugins)serializer.Deserialize(reader);
}

- Стэн

Вы можете прочитать файл в виде текста, удалить оскорбительный текст пространства имен, а затем десериализовать его.

Возможно, вам потребуется записать "хороший" текст обратно в поток [memory / string / etc], чтобы вызвать десериализатор XmlSerializer.

Вам необходимо реализовать IXmlSerializable для улучшения вашей пользовательской сериализации.

Comments

    Ничего не найдено.