2010-09-09 21 views
12

Próbuję programowo wygenerować xs: schema z dowolnego typu .net. Wiem, że mógłbym użyć refleksji i wygenerować ją przez iterację nad nieruchomościami publicznymi, ale czy jest to wbudowane?Jak programowo wygenerować schemat XML z typu?

Przykład:

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

Pożądany wyjściowa:

<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 wątpliwość istnieje sposób, aby to zrobić w ogólnym przypadku. Ponadto serial "Serializable" nie jest używany przez Serializer XML. –

+0

@John tego nie wiedział, dzięki! –

Odpowiedz

9

Tak to działa, myślę, że to nie był tak brzydki, jak się wydawało:

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

ja wciąż nadzieją, było to rozwiązanie 2 linia tam, wydaje się, że powinno być, dzięki za cynk @dtb


EDIT tylko dla WWI jaw, oto wersja 2 linia (self deprecjację humor)

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

Po prostu znalazłem się w podobnym problemie jak twój. Próbowałem użyć twojego kodu, zastępując 'nowy schemat()' z już istniejącą zmienną 'XmlSchema', ale to nie działa. Czy możesz dokładniej wyjaśnić, jak działa twoje rozwiązanie? – pyon

+0

Czy jest coś w istniejącym już XmlSchema? Soap Reflect importer jest wewnętrzną klasą używaną przez .Net Framework dla serwisów internetowych, jak sądzę. Jest na niej dokumentacja msdn. –

+0

Witam, właśnie zamierzam odrzucić [edit] (http://stackoverflow.com/suggested-edits/266125), ponieważ modyfikuje to twój kod. Możesz to sprawdzić (i powiązany komentarz), aby sprawdzić, czy są prawidłowe. – Benjol

6

Można programowo wywołać xsd.exe:

  1. Dodaj xsd.exe jako odniesienie montażowej.
  2. using XsdTool;
  3. Xsd.Main(new[] { "myassembly.dll", "/type:MyNamespace.MyClass" });

Można również użyć reflektor spojrzeć na XsdTool.Xsd.ExportSchemas metod. Używa klas publicznych XmlReflectionImporter, XmlSchemas, XmlSchema i XmlTypeMapping do tworzenia schematu z typów .NET.

Zasadniczo robi to:

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(...); 
}     ↑ 

Powinieneś być w stanie dostosować wyjście przekazując odpowiednią nagrywarkę metody XmlSchema.Write.

+0

To interesujące, nie wiedziałem, że możesz to zrobić. Nie do końca tego, czego szukam. Powodem, aby zrobić to programowo, byłoby kontrolowanie wydajności. –

+0

Rzeczywiście już to zrobiłem. To rodzaj gromady, miałem nadzieję, że ktoś zna lepszy sposób. –

1

Wierzę, że to jest to, czego szukasz: Writing your own XSD.exe

kodu Pożyczanie z góry:

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

Z pewnością już wiesz, że nie można opublikować odpowiedzi z łączem? –

+1

@JohnSaunders: Debatowałem nad tym przez kilka minut przed opublikowaniem, ale nie mogłem wymyślić użytecznego podsumowania (poza opublikowaniem całego programu na blogu). Jedynym ryzykiem jest to, że ten post nie jest zsynchronizowany z żadnymi aktualizacjami z tego miejsca. Co polecasz? – Mrchief

+0

Usunięcie go, zanim zostanie usunięty, byłoby moją rekomendacją, chyba że możesz wymyślić podsumowanie. –

13

znalazłem accepted answer wygenerował niepoprawny schemat podając niektóre z moich atrybutów. na przykładTo ignorowane nazwy niestandardowe wartości enum oznaczonych [XmlEnum(Name="Foo")]

Wierzę, że to jest prawidłowy sposób (podane używasz XmlSerializer) i jest dość prosty zbyt:

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

Kod wydobywać: http://blogs.msdn.com/b/youssefm/archive/2010/05/13/using-xml-schema-import-and-export-for-xmlserializer.aspx

+0

Pozdrawiam, dzięki za aktualizację. –

Powiązane problemy