2010-09-09 4 views
12

Я пытаюсь создать xs: schema из любого .net Тип программно. Я знаю, что могу использовать отражение и генерировать его, итерации по публичным свойствам, но есть ли встроенный способ?Как программно генерировать xml-схему из типа?

Пример:

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

Желаемая Выход:

<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 сомневаюсь, что есть способ сделать это в общем случае. Кроме того, '[Serializable]' не используется XML-сериализатором. –

+0

@ Джон не знал этого, спасибо! –

ответ

9

Так что это работает, я предполагаю, что это было не так уродливо, как казалось:

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

я все еще надеялся, там было 2 линии решения там, кажется, что там должно быть, спасибо за наконечник @dtb


EDIT Только для KIC кс, вот версия 2 линии (сам осуждающий юмор)

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

Я просто оказался в проблеме, подобной вашей. Я попытался использовать ваш код, заменив 'new Schema()' на уже существующую переменную 'XmlSchema', но она не работает. Не могли бы вы объяснить, как работает ваше решение? – pyon

+0

Есть ли что-нибудь в уже существующем XmlSchema? Импортёр мыльного отражения является внутренним классом, который, как я полагаю, используется .NET Framework для веб-сервисов. На нем есть документация msdn. –

+0

Привет, я собираюсь отклонить [edit] (http://stackoverflow.com/spected-edits/266125), потому что он изменяет ваш код. Вы можете проверить его (и соответствующий комментарий), чтобы узнать, действительны ли они. – Benjol

6

Вы можете программно вызывать xsd.exe:

  1. Добавить xsd.exe в качестве ссылки на сборку.
  2. using XsdTool;
  3. Xsd.Main(new[] { "myassembly.dll", "/type:MyNamespace.MyClass" });

Вы также можете использовать отражатель, чтобы посмотреть на XsdTool.Xsd.ExportSchemas метода. Он использует общедоступные классы XmlReflectionImporter, XmlSchemas, XmlSchemaXmlSchemaExporter и XmlTypeMapping классы для создания схемы из типов .NET.

По сути он делает это:

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

Вы должны быть в состоянии настроить вывод, передавая соответствующий писатель методу XmlSchema.Write.

+0

Это интересно, я не знал, что вы можете это сделать. Не совсем то, что я ищу. Причиной делать это программно было бы управление выходом. –

+0

Я уже это сделал. Это своего рода кластер, я надеялся, что кто-то знает лучший способ. –

0

Средство определения схемы XML генерирует XML-схемы или классы времени выполнения обычного языка из XDR, XML и XSD-файлов или из классов в сборке времени выполнения.

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

+1

Запуск .exe не считается программным. –

+0

Вы всегда можете запустить .exe из своего кода. ;) – JBeurer

1

Я считаю, что это то, что вы ищете: Writing your own XSD.exe

код заимствования из выше:

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

Наверняка, теперь вы знаете лучше, чем публиковать ответ только для ссылок? –

+1

@JohnSaunders: Я обсуждал это несколько минут, прежде чем публиковать его, но я не мог найти полезное резюме (кроме публикации всей программы для блога). Только риск с этим - это сообщение, выходящее из синхронизации с любыми обновлениями оттуда. Что вы порекомендуете? – Mrchief

+0

Удаление его до того, как оно будет удалено для вас, станет моей рекомендацией, если вы не придумаете резюме. –

13

Я нашел accepted answer генерирует неправильную схему с некоторыми моими атрибутами. напримерОн игнорировал пользовательские имена для значений перечислений, обозначенных [XmlEnum(Name="Foo")]

Я считаю, что это правильный путь (учитывая ваше использование XmlSerializer) и довольно просто тоже:

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

Код извлеченный из: http://blogs.msdn.com/b/youssefm/archive/2010/05/13/using-xml-schema-import-and-export-for-xmlserializer.aspx

+0

Приветствия, спасибо за обновление. –

Смежные вопросы