2010-09-09 9 views
12

Sto provando a generare uno schema xs: da qualsiasi tipo .net a livello di codice. So che potrei usare la riflessione e generarla iterando sulle proprietà pubbliche, ma c'è un modo integrato?Come posso generare uno schema XML da un tipo al livello di programmazione?

Esempio:

[Serializable] 
public class Person 
{ 
    [XmlElement(IsNullable = false)] public string FirstName { get; set; } 
    [XmlElement(IsNullable = false)] public string LastName { get; set; } 
    [XmlElement(IsNullable = true)] public string PhoneNo { get; set; } 
} 

output desiderato:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="Person" type="Person" /> 
    <xs:complexType name="Person"> 
    <xs:sequence> 
     <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="FirstName" type="xs:string" /> 
     <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="LastName" type="xs:string" /> 
     <xs:element minOccurs="0" maxOccurs="1" form="unqualified" name="PhoneNo" type="xs:string" /> 
    </xs:sequence> 
    </xs:complexType> 
</xs:schema> 
+0

I dubbio c'è un modo per farlo nel caso generale. Inoltre, '[Serializable]' non è usato dal Serializer XML. –

+0

@ John non lo sapeva, grazie! –

risposta

9

Quindi questo funziona, credo che non era così brutta come sembrava:

var soapReflectionImporter = new SoapReflectionImporter(); 
var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Person)); 
var xmlSchemas = new XmlSchemas(); 
var xmlSchema = new XmlSchema(); 
xmlSchemas.Add(xmlSchema); 
var xmlSchemaExporter = new XmlSchemaExporter(xmlSchemas); 
xmlSchemaExporter.ExportTypeMapping(xmlTypeMapping); 

Speravo ancora ci fosse una soluzione a 2 linee là fuori, sembra che ci dovrebbe essere, grazie per il suggerimento @dtb


EDIT Solo per KIC ks, ecco la versione a 2 linee (auto ironico umorismo)

var typeMapping = new SoapReflectionImporter().ImportTypeMapping(typeof(Person)); 
new XmlSchemaExporter(new XmlSchemas { new XmlSchema() }).ExportTypeMapping(typeMapping); 
+0

Mi sono appena trovato in un problema simile al tuo. Ho provato a usare il tuo codice, sostituendo 'new Schema()' con una variabile 'XmlSchema' già esistente, ma non funziona. Potresti spiegare ulteriormente come funziona la tua soluzione? – pyon

+0

C'è qualcosa nel XmlSchema già esistente? Credo che l'importatore di riflessioni di sapone sia una classe interna utilizzata dal .Net Framework per i servizi web. C'è una documentazione di msdn su di esso. –

+0

Ciao, sto per rifiutare un [modifica] (http://stackoverflow.com/suggested-edits/266125) perché modifica il tuo codice. Potresti voler controllare (e commentare i commenti) per vedere se sono validi. – Benjol

6

di programmazione è possibile richiamare xsd.exe:

  1. Aggiungi xsd.exe come riferimento di montaggio.
  2. using XsdTool;
  3. Xsd.Main(new[] { "myassembly.dll", "/type:MyNamespace.MyClass" });

È anche possibile utilizzare Reflector di guardare ai XsdTool.Xsd.ExportSchemas metodo. Utilizza le classi pubbliche XmlReflectionImporter, XmlSchemas, XmlSchemaXmlSchemaExporter e XmlTypeMapping per creare uno schema da tipi .NET.

Essenzialmente si fa questo:

var importer = new XmlReflectionImporter(); 
var schemas = new XmlSchemas(); 
var exporter = new XmlSchemaExporter(schemas); 

var xmlTypeMapping = importer.ImportTypeMapping(typeof(Person)); 
exporter.ExportTypeMapping(xmlTypeMapping); 

schemas.Compile(..., false); 

for (var i = 0; i < schemas.Count; i++) 
{ 
    var schema = schemas[i]; 
    schema.Write(...); 
}     ↑ 

Si dovrebbe essere in grado di personalizzare l'output, passando uno scrittore adatta al metodo XmlSchema.Write.

+0

È interessante, non sapevo che potessi farlo. Non proprio quello che sto cercando. La ragione per farlo programmaticamente sarebbe controllare l'output. –

+0

L'ho già fatto. È una specie di cluster, speravo che qualcuno conoscesse un modo migliore. –

0

Lo strumento di definizione dello schema XML genera uno schema XML o classi di runtime in linguaggio comune dai file XDR, XML e XSD o dalle classi in un assieme runtime.

http://msdn.microsoft.com/en-us/library/x6c1kb0s(VS.71).aspx

+1

L'esecuzione di un file .exe non viene considerata come programmatica. –

+0

Puoi sempre eseguire .exe dal tuo codice. ;) – JBeurer

1

Credo che questo sia quello che stai cercando: Writing your own XSD.exe

codice Prendendo in prestito dall'alto:

using System; 
using System.IO; 
using System.Collections.Generic; 
using System.Reflection; 
using System.Text; 
using System.Xml; 
using System.Xml.Serialization; 
using System.Xml.Schema; 
using System.CodeDom; 
using System.CodeDom.Compiler; 

using Microsoft.CSharp; 

using NUnit.Framework; 

namespace XmlSchemaImporterTest 
{ 
    [TestFixture] 
    public class XsdToClassTests 
    { 
     // Test for XmlSchemaImporter 
     [Test] 
     public void XsdToClassTest() 
     { 
      // identify the path to the xsd 
      string xsdFileName = "Account.xsd"; 
      string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
      string xsdPath = Path.Combine(path, xsdFileName); 

      // load the xsd 
      XmlSchema xsd; 
      using(FileStream stream = new FileStream(xsdPath, FileMode.Open, FileAccess.Read)) 
      { 
       xsd = XmlSchema.Read(stream, null); 
      } 
      Console.WriteLine("xsd.IsCompiled {0}", xsd.IsCompiled); 

      XmlSchemas xsds = new XmlSchemas(); 
      xsds.Add(xsd); 
      xsds.Compile(null, true); 
      XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds); 

      // create the codedom 
      CodeNamespace codeNamespace = new CodeNamespace("Generated"); 
      XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace); 

      List maps = new List(); 
      foreach(XmlSchemaType schemaType in xsd.SchemaTypes.Values) 
      { 
       maps.Add(schemaImporter.ImportSchemaType(schemaType.QualifiedName)); 
      } 
      foreach(XmlSchemaElement schemaElement in xsd.Elements.Values) 
      { 
       maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName)); 
      } 
      foreach(XmlTypeMapping map in maps) 
      { 
       codeExporter.ExportTypeMapping(map); 
      } 

      RemoveAttributes(codeNamespace); 

      // Check for invalid characters in identifiers 
      CodeGenerator.ValidateIdentifiers(codeNamespace); 

      // output the C# code 
      CSharpCodeProvider codeProvider = new CSharpCodeProvider(); 

      using(StringWriter writer = new StringWriter()) 
      { 
       codeProvider.GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions()); 
       Console.WriteLine(writer.GetStringBuilder().ToString()); 
      } 

      Console.ReadLine(); 
     } 

     // Remove all the attributes from each type in the CodeNamespace, except 
     // System.Xml.Serialization.XmlTypeAttribute 
     private void RemoveAttributes(CodeNamespace codeNamespace) 
     { 
      foreach(CodeTypeDeclaration codeType in codeNamespace.Types) 
      { 
       CodeAttributeDeclaration xmlTypeAttribute = null; 
       foreach(CodeAttributeDeclaration codeAttribute in codeType.CustomAttributes) 
       { 
        Console.WriteLine(codeAttribute.Name); 
        if(codeAttribute.Name == "System.Xml.Serialization.XmlTypeAttribute") 
        { 
         xmlTypeAttribute = codeAttribute; 
        } 
       } 
       codeType.CustomAttributes.Clear(); 
       if(xmlTypeAttribute != null) 
       { 
        codeType.CustomAttributes.Add(xmlTypeAttribute); 
       } 
      } 
     } 
    } 
} 
+1

Sicuramente ormai sai meglio di pubblicare una risposta solo per link? –

+1

@JohnSaunders: l'ho discusso per alcuni minuti prima di postarlo, ma non riuscivo a capire un utile sommario (oltre a postare l'intero programma per il blog). Solo il rischio è che questo post non sia sincronizzato con gli aggiornamenti da lì. Che cosa mi consiglia? – Mrchief

+0

Cancellarlo prima che venga eliminato per te sarebbe la mia raccomandazione, a meno che tu non riesca a trovare un riassunto. –

13

ho trovato il accepted answer ha generato uno schema errato dati alcuni dei miei attributi. per esempio.E 'ignorato nomi personalizzati per i valori enum contrassegnati con [XmlEnum(Name="Foo")]

Credo che questo sia il modo corretto (dato la vostra utilizzando XmlSerializer) ed è abbastanza semplice anche:

var schemas = new XmlSchemas(); 
var exporter = new XmlSchemaExporter(schemas); 
var mapping = new XmlReflectionImporter().ImportTypeMapping(typeof(Person)); 
exporter.ExportTypeMapping(mapping); 
var schemaWriter = new StringWriter(); 
foreach (XmlSchema schema in schemas) 
{ 
    schema.Write(schemaWriter); 
} 
return schemaWriter.ToString(); 

Codice estratto da: http://blogs.msdn.com/b/youssefm/archive/2010/05/13/using-xml-schema-import-and-export-for-xmlserializer.aspx

+0

Ciao, grazie per l'aggiornamento. –

Problemi correlati