2008-12-03 14 views
5

Uso la serialización XML para la lectura de mis Config-POCOs.Serialización XML y esquema sin xsd.exe

Para obtener soporte intellisense en Visual Studio para archivos XML, necesito un archivo de esquema. Puedo crear el esquema con xsd.exe mylibrary.dll y esto funciona bien.

Pero quiero que el esquema siempre se cree si serializo un objeto al sistema de archivos. ¿Hay alguna forma sin usar xsd.exe?

Respuesta

11

gracias, este fue el camino correcto para mí. solución:

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

Ahora que te veo código, se 've' lo que hice camino de vuelta (solo el recuerdo no puede dónde!) – leppie

11

La solución fue anunciado anteriormente por Will funcionó de maravilla, excepto que me di cuenta que el esquema generado no refleja los atributos de los diferentes miembros de la clase. Por ejemplo, una clase decorada con atributos de pistas de serialización (ver el ejemplo a continuación) no se habría procesado correctamente.

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

    } 

Para hacer frente a esto, he creado un par de funciones de ayuda que utilizan la reflexión de atravesar la jerarquía de clases, leer los atributos, y poblar un objeto XmlAttributeOverrides que se puede pasar en el 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(); 
     } 
    } 

Espero que esto ayude a alguien más.

+0

Cómo aplicar XmlAttributes de forma recursiva para tipos de usuario de propiedad anidada? Por ejemplo CustomerClass? –

0

Mejora de la versión de Matt Murrell: para aplicar XmlAttributes de forma recursiva para el tipo de usuario de propiedades anidadas (por ejemplo, la propiedad 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; 
}