2008-12-03 9 views
5

J'utilise la sérialisation XML pour la lecture de mes Config-POCO. Pour obtenir la prise en charge d'IntelliSense dans Visual Studio pour les fichiers XML, j'ai besoin d'un fichier de schéma.Sérialisation XML et schéma sans xsd.exe

Je peux créer le schéma avec xsd.exe mylibrary.dll et cela fonctionne très bien.

Mais je veux que le schéma soit toujours créé si je sérialise un objet dans le système de fichiers. Est-il possible sans utiliser xsd.exe?

Répondre

11

merci, c'était la bonne façon pour moi. solution :

XmlReflectionImporter importer = new XmlReflectionImporter(); 
XmlSchemas schemas = new XmlSchemas(); 
XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); 
Type type = toSerialize.GetType(); 
XmlTypeMapping map = importer.ImportTypeMapping(type); 
exporter.ExportTypeMapping(map); 

TextWriter tw = new StreamWriter(fileName + ".xsd"); 
schemas[0].Write(tw); 
tw.Close(); 
+0

Maintenant que je vous vois code, il semble «ce que je faisais le chemin du retour (juste rappel ne peux pas où!) – leppie

11

La solution affiché ci-dessus par Will a fonctionné à merveille, sauf que je compris que le schéma généré ne reflète pas les attributs sur les différents membres de la classe. Par exemple, une classe décorée avec des attributs d'indice de sérialisation (voir l'exemple ci-dessous) n'aurait pas été rendue correctement.

public class Test 
    { 
     [XmlAttribute()] 
     public string Attribute { get; set; } 
     public string Description { get; set; } 

     [XmlArray(ElementName = "Customers")] 
     [XmlArrayItem(ElementName = "Customer")] 
     public List<CustomerClass> blah { get; set; } 

    } 

Pour résoudre ce problème, j'ai créé quelques fonctions d'aide qui utilisent la réflexion pour parcourir la hiérarchie des classes, lisez les attributs, et remplir un objet XmlAttributeOverrides qui peut être transmis dans le XmlReflectionImporter.

public static void AttachXmlAttributes(XmlAttributeOverrides xao, Type t) 
    { 
     List<Type> types = new List<Type>(); 
     AttachXmlAttributes(xao, types, t); 
    } 

    public static void AttachXmlAttributes(XmlAttributeOverrides xao, List<Type> all, Type t) 
    { 
     if(all.Contains(t)) 
      return; 
     else 
      all.Add(t); 

     XmlAttributes list1 = GetAttributeList(t.GetCustomAttributes(false)); 
     xao.Add(t, list1); 

     foreach (var prop in t.GetProperties()) 
     { 
      XmlAttributes list2 = GetAttributeList(prop.GetCustomAttributes(false)); 
      xao.Add(t, prop.Name, list2); 
      AttachXmlAttributes(xao, all, prop.PropertyType); 
     } 
    } 

    private static XmlAttributes GetAttributeList(object[] attributes) 
    { 
     XmlAttributes list = new XmlAttributes(); 
     foreach (var attribute in attributes) 
     { 
      Type type = attribute.GetType(); 
      if (type.Name == "XmlAttributeAttribute") list.XmlAttribute = (XmlAttributeAttribute)attribute; 
      else if (type.Name == "XmlArrayAttribute") list.XmlArray = (XmlArrayAttribute)attribute; 
      else if (type.Name == "XmlArrayItemAttribute") list.XmlArrayItems.Add((XmlArrayItemAttribute)attribute); 

     } 
     return list; 
    } 
    public static string GetSchema<T>() 
    { 
     XmlAttributeOverrides xao = new XmlAttributeOverrides(); 
     AttachXmlAttributes(xao, typeof(T)); 

     XmlReflectionImporter importer = new XmlReflectionImporter(xao); 
     XmlSchemas schemas = new XmlSchemas(); 
     XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); 
     XmlTypeMapping map = importer.ImportTypeMapping(typeof(T)); 
     exporter.ExportTypeMapping(map); 

     using (MemoryStream ms = new MemoryStream()) 
     { 
      schemas[0].Write(ms); 
      ms.Position = 0; 
      return new StreamReader(ms).ReadToEnd(); 
     } 
    } 

Espérons que cela aide quelqu'un d'autre.

+0

Comment appliquer XmlAttributes récursive pour les types d'utilisateurs de propriété imbriqué? Par exemple CustomerClass? –

0

Amélioration de la version de Matt Murrell: application de XmlAttributes récursivement au type d'utilisateur de propriété imbriqué (par exemple, propriété CustomerClass).

private static void AttachXmlAttributes(XmlAttributeOverrides xao, List<Type> all, Type t) 
{ 
    if (all.Contains(t)) 
    { 
     return; 
    } 
    else 
    { 
     all.Add(t); 
    } 

    var list1 = GetAttributeList(t.GetCustomAttributes(false)); 
    xao.Add(t, list1); 

    foreach (var prop in t.GetProperties()) 
    { 
     var propType = prop.PropertyType; 
     if (propType.IsGenericType) // is list? 
     { 
      var args = propType.GetGenericArguments(); 
      if (args != null && args.Length == 1) 
      {       
       var genType = args[0]; 
       if (genType.Name.ToLower() != "object") 
       { 
        var list2 = GetAttributeList(prop.GetCustomAttributes(false)); 
        xao.Add(t, prop.Name, list2); 
        AttachXmlAttributes(xao, all, genType); 
       }       
      } 
     } 
     else 
     { 
      var list2 = GetAttributeList(prop.GetCustomAttributes(false)); 
      xao.Add(t, prop.Name, list2); 
      AttachXmlAttributes(xao, all, prop.PropertyType); 
     } 
    } 
}   

private static XmlAttributes GetAttributeList(object[] attributes) 
{ 
    var list = new XmlAttributes(); 
    foreach (var attr in attributes) 
    { 
     Type type = attr.GetType(); 
     switch (type.Name) 
     { 
      case "XmlAttributeAttribute": 
       list.XmlAttribute = (XmlAttributeAttribute)attr; 
       break;      
      case "XmlRootAttribute": 
       list.XmlRoot = (XmlRootAttribute)attr; 
       break; 
      case "XmlElementAttribute": 
       list.XmlElements.Add((XmlElementAttribute)attr); 
       break; 
      case "XmlArrayAttribute": 
       list.XmlArray = (XmlArrayAttribute)attr; 
       break; 
      case "XmlArrayItemAttribute": 
       list.XmlArrayItems.Add((XmlArrayItemAttribute)attr); 
       break; 
     } 
    } 
    return list; 
}