2008-10-16 7 views
1

Ma question est la suivante.Quel est le meilleur moyen de sérialiser le xml dans les objets appropriés lors de la version par espaces de noms?

J'ai un fichier XML qui est versionné par un espace de noms. Je veux sérialiser ce xml reçu dans l'objet approprié, mais la seule façon que je connaisse de le faire signifie que je dois traiter le xml deux fois. Tout d'abord pour découvrir l'espace de noms, puis afin de sérialiser l'objet du type approprié en fonction de l'espace de noms découvert. Cela me semble terriblement inefficace, et il doit y avoir un moyen d'utiliser des génériques ou quelque chose pour récupérer le type d'objet approprié sans un contrôle 'if namespace == x then serialze to this'.

Voici un exemple de la seule façon que je connaisse pour accomplir cela. Y a-t-il un moyen meilleur ou plus efficace?

Merci

using System; 
using System.Text; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System.Xml.Linq; 
using System.Xml; 
using System.Xml.Serialization; 
using System.IO; 

namespace TestProject1 
{ 
    [TestClass] 
    public class UnitTest1 
    { 
     [TestMethod] 
     public void TestMethod3() 
     { 
      //Build up an employee object to xml 
      Schema.v2.Employee employee = new Schema.v2.Employee { FirstName = "First", LastName = "Last" }; 
      string xml = employee.ObjectToXml<Schema.v2.Employee>(); 

      //Now pretend I don't know what type I am receiving. 
      string nameSpace = GetNamespace(xml); 
      Object newemp; 
      if (nameSpace == "Employee.v2") 
       newemp = XmlSerializationExtension.XmlToObject<Schema.v2.Employee>(null, xml); 
      else 
       newemp = XmlSerializationExtension.XmlToObject<Schema.v1.Employee>(null, xml); 

      // Check to make sure that the type I got was what I made. 
      Assert.AreEqual(typeof(Schema.v2.Employee), newemp.GetType()); 
     } 

     public string GetNamespace(string s) 
     { 
      XDocument z = XDocument.Parse(s); 
      var result = z.Root.Attributes(). 
        Where(a => a.IsNamespaceDeclaration). 
        GroupBy(a => a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName, 
          a => XNamespace.Get(a.Value)). 
        ToDictionary(g => g.Key, 
           g => g.First()); 

      foreach (System.Xml.Linq.XNamespace item in result.Values) 
       if (item.NamespaceName.Contains("Employee")) return item.NamespaceName; 

      return String.Empty; 
     } 
    } 

    public static class XmlSerializationExtension 
    { 
     public static string ObjectToXml<T>(this T Object) 
     { 
      XmlSerializer s = new XmlSerializer(Object.GetType()); 
      using (StringWriter writer = new StringWriter()) 
      { 
       s.Serialize(writer, Object); 
       return writer.ToString(); 
      } 
     } 
     public static T XmlToObject<T>(this T Object, string xml) 
     { 
      XmlSerializer s = new XmlSerializer(typeof(T)); 
      using (StringReader reader = new StringReader(xml)) 
      { 
       object obj = s.Deserialize(reader); 
       return (T)obj; 
      } 
     } 
    } 
} 

namespace Schema.v1 
{ 
    [XmlRoot(ElementName = "Employee", Namespace= "Employee.v1", IsNullable = false)] 
    public class Employee 
    { 
     [XmlElement(ElementName = "FirstName")] 
     public string FirstName { get; set; } 
     [XmlElement(ElementName = "LastName")] 
     public string LastName { get; set; } 
    } 
} 
namespace Schema.v2 
{ 
    [XmlRoot(ElementName = "Employee", Namespace = "Employee.v2", IsNullable = false)] 
    public class Employee 
    { 
     [XmlAttribute(AttributeName = "FirstName")] 
     public string FirstName { get; set; } 
     [XmlAttribute(AttributeName = "LastName")] 
     public string LastName { get; set; } 
    } 
} 

Répondre

1

Deux suggestions:

Tout d'abord, peut-être ne le font pas du tout. Si vous procédez à la sérialisation, préférez une méthode plutôt qu'une autre à moins que l'appelant ne spécifie un schéma. Deuxièmement, n'analysez pas le XML pour la découverte; faites simplement une chaîne correspondant à "Employee.v2" et "Employee.v1" dans (disons) les 100 premiers octets du fichier (ou aussi loin que vous devez aller pour obtenir l'information). Cela devrait fonctionner, à moins que ceux-ci ne soient des chaînes courantes dans vos données.

+0

Oui, l'appelant me soumet le fichier XML. Si aucun espace de noms, alors j'ai besoin d'utiliser la version 1, mais si l'espace de noms est la version 2, alors le format du xml et tous les éléments incorporés peuvent être radicalement différents. Oui, je peux créer une autre méthode de saisie pour l'appelant, mais les interfaces changent ensuite. – degnome

+0

Deuxième option que je pense à ce sujet, semble être une très bonne option, s'il n'y a pas moyen de le faire directement au moment de la sérialisation. – degnome