2010-02-19 5 views
3

double:
Omitting all xml namespaces when serializing an object? Pas même .. Je veux dans l'autre sens: Désérialise!XML Deserialize sans espaces de noms, mais dans une classe attend des espaces de noms


J'ai une classe C# comme ci-dessous:

[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 
    { ... 

J'utilise cette classe pour sérialisation/délinéariser fichiers XML demande de l'utilisateur. Mais j'ai un problème: la définition des espaces de noms a été ajoutée sur la nouvelle version de ce logiciel. Le code XML est toujours le même, en ajoutant uniquement la définition des espaces de noms.

Ex., Dernière version ...

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

et nouvelle version ...

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

J'ai besoin de charger des fichiers XML avec et sans ces espaces de noms. J'ai beaucoup de classes imbriquées et chacune a sa propre définition d'espaces de noms.

Je voudrais utiliser les mêmes classes pour les deux XML, avec et sans espaces de noms.

J'ai essayé de créer un XmlTextReader et d'écraser la méthode NamespaceURI, mais je reçois toujours une exception avec peu d'informations. Je pense que le moteur de .NET essaye de forcer la définition d'espace de noms de classe contre le XML.

+0

Salut, est votre requête résolue? –

+0

Arijit, je l'ai résolu en utilisant une approche différente. Malheureusement, il n'y a aucun moyen de faire ce que je voulais comme je le voulais (en utilisant moins de code que possible). J'ai donc utilisé XmlTextReader pour certains webservices et sur d'autres j'ai sérialisé le Xml entier dans une chaîne et j'ai supprimé les espaces de noms inutilisés en utilisant String.Replace. Ce n'est pas la meilleure chose à faire, mais cela s'est également avéré être une bonne chose. – rodrigogq

+0

Merci pour la réponse, en fait mon problème vous ressemble, la réponse donnée ci-dessous ne fonctionne pas je suppose. Pouvez-vous montrer comment vous l'avez fait? Cela fait 4 ans que Microsoft n'a pas pensé à ça? –

Répondre

6

J'avais rencontré un défi similaire avec une classe proxy. Pour des raisons que je n'aborderai pas, je devais sérialiser manuellement la classe en utilisant XmlSerializer sur le serveur web et désérialiser sur le client. Je n'étais pas en mesure de trouver une solution élégante en ligne, j'ai donc évité le problème en supprimant XmlTypeAttribute de la classe proxy manuellement après l'avoir générée automatiquement dans Visual Studio.

Je revenais régulièrement pour voir s'il y avait un moyen de faire fonctionner l'espace de nom. Voici comment je l'ai fait fonctionner sans avoir besoin de modifier les classes générées automatiquement. J'ai fini par utiliser un XmlTextReader pour retourner l'espace de noms désiré sur les nœuds correspondant à un nom de propriété. Il y a place à amélioration, mais j'espère que cela aidera quelqu'un.

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; 
     } 
    } 
} 
+0

Salut GLass, je suis presque dans un problème similaire, besoin d'aide –

+0

Brilliant le lecteur proxy Soap -> Merci beaucoup. – Titwan

-1

Vous devez implémenter IXmlSerializable pour améliorer votre sérialisation personnalisée.

+1

J'ai beaucoup de classes imbriquées. Serait terrible de l'implémenter sur chacune de ces classes juste pour supprimer les espaces de noms !!!! Je devrais ajouter un XmlSchemaProvider pour chaque classe, renvoyant des schémas différents selon la version. N'y a-t-il pas un moyen plus facile de désérialiser? Tout comme ajouter une chaîne d'espace de noms vide à la fonction sérialiser? – rodrigogq

1

Vous pouvez lire le fichier en tant que texte, supprimer le texte de l'espace de noms incriminé, puis le désérialiser.

Vous devrez peut-être réécrire le "bon" texte dans un flux [memory/string/etc] afin que la désérialisation de XmlSerializer puisse être appelée.

+0

Oui ... cela semble être le "meilleur" moyen. Tks! – rodrigogq

5

Pour désérialiser XML sans espace de noms ajouter attribut XmlRoot à la classe qui représente le sommet de la hiérarchie:

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

Dans mon exemple, le Xml n'a aucun espace de noms et commence comme

<plugins><... 

La classe désérialisée à:

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

De toute évidence, votre situation est peut-être un peu différent, mais ce code fonctionne pour moi:

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); 
} 

-stan