2009-09-10 17 views
12

GPX dosyalarını okumak/yazmak için bir C# sınıfı oluşturmak için xsd.exe'yi kullandım. Sonuç xsi: schemaLocation özniteliği 'u dahil etmek için sonuç XML dosyasını nasıl alabilirim. schemaLocation hepXmlSerialization ve xsi: SchemaLocation (xsd.exe)

<?xml version="1.0"?> 
<gpx 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    version="1.1" 
    xmlns="http://www.topografix.com/GPX/1/1" 
    creator="ExpertGPS 1.1 - http://www.topografix.com" 
    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"> 
</gpx> 

cevap

33

Oluşturulan C# sınıfına bu ekleyin eksik::

[XmlAttribute("schemaLocation", Namespace = XmlSchema.InstanceNamespace)] 
public string xsiSchemaLocation = "http://www.topografix.com/GPX/1/1 " + 
            "http://www.topografix.com/GPX/1/1/gpx.xsd"; 

Görünüşe xsd.exe aracı does not generateschemaLocation nitelik

Aşağıdaki ama xsi istiyorum.

+0

Mükemmel teşekkürler! –

+0

ŞemaKonum ne için ayarlandı? XSD.EXE'nin kullandığı yer, xsi: schemaLocation kullanıcısının kullanıcının bulması gereken web'de bulunma olasılığı düşüktür. –

+0

@John: Belki xsd dosyasındaki değeri belirtmek için bir seçenek var mı? – dtb

2

Bunu kendi başınıza yapmanız gerekecektir. XML Serileştirme'nin şemanızın nereye gitmesini istediğinizi bilmesinin bir yolu yoktur. Henüz test etmedim gerçi

, bu deneyin:

Tabii
[XmlRoot(ElementName = "gpx", Namespace = GPX_NAMESPACE)] 
public class WhateverAGpxIs 
{ 
    private const string GPX_NAMESPACE = "http://www.topografix.com/GPX/1/1"; 

    private const string XSI_NAMESPACE = 
     "http://www.w3.org/2001/XMLSchema-instance"; 

    [XmlAttribute(AttributeName = "creator")] 
    public string Creator = "ExpertGPS 1.1 - http://www.topografix.com"; 

    [XmlNamespaceDeclarations] 
    public XmlSerializerNamespaces Namespaces = 
     new XmlSerializerNamespaces(
      new[] 
       { 
        new XmlQualifiedName("xsi", XSI_NAMESPACE), 
        new XmlQualifiedName(string.Empty, GPX_NAMESPACE) 
       }); 

    [XmlAttribute(AttributeName = "schemaLocation", 
     Namespace = XSI_NAMESPACE)] 
    public string SchemaLocation = GPX_NAMESPACE + " " + 
            "http://www.topografix.com/GPX/1/1/gpx.xsd"; 

    [XmlAttribute(AttributeName = "version")] 
    public string Version = "1.1"; 
} 
2

Bu cevap yolu çok geç! Ama belki diğer geliştiriciler için yararlıdır ;-). Bu problemi çözmek için relfection kullandım, çünkü otomatik olması gerekiyordu.

Statik yöntem CreateMessageType çağrılmalıdır. schemaLocation özelliğini içeren NOT seri hale getirilmiş sınıf olmalıdır. Bu yöntem, asal (Dynamic adlı) kullanarak yeni bir tür döndürür, ancak schemaLocation özelliklerini ekler ve XmlRootAttribute öğesinin ElementName özelliğini ayarlar.

türü oluşturma sonra yansıma yeniden özellikleri bir obje yaratması ve ayarlamak için kullanılmalıdır.

kod xxx oldukça ağrı gibi görünüyor, ama bir cazibe gibi çalışır!

/// <summary>Copying the attributes of a type to a new type</summary> 
private static void copyAttributes<TMessage>(TypeBuilder dynamictype) 
{ 
    try 
    { 
     //Iterate over all attributes of the TMessage class and copy these to the new type 
     IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(typeof(TMessage)); 
     if (attributes != null) 
     { 
      foreach (CustomAttributeData attribute in attributes) 
      { 
       List<object> constructorarguments = new List<object>(); 
       if (attribute.ConstructorArguments != null) 
       { 
        foreach (CustomAttributeTypedArgument argument in attribute.ConstructorArguments) 
        { 
         constructorarguments.Add(argument.Value); 
        } 
       } 

       List<FieldInfo> namedfields = new List<FieldInfo>(); 
       List<object> namedfieldarguments = new List<object>(); 

       List<PropertyInfo> namedproperties = new List<PropertyInfo>(); 
       List<object> namedpropertyarguments = new List<object>(); 

       if (attribute.NamedArguments != null) 
       { 
        //Iterate over all named arguments 
        foreach (CustomAttributeNamedArgument argument in attribute.NamedArguments) 
        { 
         //Check which type of argument is found 
         if (argument.MemberInfo is FieldInfo) 
         { 
          FieldInfo field = argument.MemberInfo as FieldInfo; 
          namedfields.Add(field); 
          namedfieldarguments.Add(argument.TypedValue.Value); 
         } 
         else if (argument.MemberInfo is PropertyInfo) 
         { 
          PropertyInfo property = argument.MemberInfo as PropertyInfo; 
          namedproperties.Add(property); 
          namedpropertyarguments.Add(argument.TypedValue.Value); 
         } 
        } 
       } 

       //Check if the current attribute is of type XmlRoot. 
       //In this case the ElementName or TypeName property must also be set 
       if (attribute.Constructor.DeclaringType.Equals(typeof(XmlRootAttribute))) 
       { 
        namedproperties.Add(typeof(XmlRootAttribute).GetProperty("ElementName")); 
        namedpropertyarguments.Add(typeof(TMessage).Name); 
       } 

       //Build the copy of the parent attribute 
       CustomAttributeBuilder copyattributebuilder = new CustomAttributeBuilder(
        attribute.Constructor, 
        constructorarguments.ToArray(), 
        namedproperties.ToArray(), 
        namedpropertyarguments.ToArray(), 
        namedfields.ToArray(), 
        namedfieldarguments.ToArray()); 

       //Add the attribute to the dynamic type 
       dynamictype.SetCustomAttribute(copyattributebuilder); 
      } 
     } 
    } 
    catch (Exception exception) 
    { 
     throw new ApplicationException("Unable to copy attribute from parent type", exception); 
    } 
} 

/// <summary>Create dynamic type for an operation message which includes the types for serialization</summary> 
/// <returns>Returns dynamic type</returns> 
public static Type CreateMessageType<TMessage>() 
{ 
    try 
    { 
     AssemblyBuilder assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); 
      ModuleBuilder modulebuilder = assemblybuilder.DefineDynamicModule(Guid.NewGuid().ToString(), false); 

      //Create type based on an unique so that it does not conflict with the OperationMessage classname 
      TypeBuilder typebuilder = modulebuilder.DefineType(typeof(TMessage).Name + "Dynamic", TypeAttributes.Public | TypeAttributes.Class); 

      //Set original message type as parent of the new dynamic type 
      typebuilder.SetParent(typeof(TMessage)); 

      //Copy attributes from TMessage paren type to the dynamic type 
      WMQXMLMessageTypeFactory.copyAttributes<TMessage>(typebuilder); 

      //Create the xsi:schemaLocation property 
      CustomAttributeBuilder attributebuilder = new CustomAttributeBuilder(
       typeof(XmlAttributeAttribute).GetConstructor(new Type[] { typeof(string) }), 
       new object[] { "schemaLocation" }, 
       new PropertyInfo[] { typeof(XmlAttributeAttribute).GetProperty("Namespace") }, 
       new object[] { XmlSchema.InstanceNamespace }); 

      FieldBuilder schemalocationfieldbuilder = typebuilder.DefineField("SchemaLocation", typeof(string), FieldAttributes.Public); 
      schemalocationfieldbuilder.SetCustomAttribute(attributebuilder); 

      return typebuilder.CreateType(); 
     } 
     catch (Exception exception) 
     { 
      throw new ApplicationException("Unable to create XML message type", exception); 
     } 
    } 

aşağıdaki Ben nesneyi

Type type = WMQXMLMessageTypeFactory.CreateMessageType<TenantRequest>(); 

MetaData metadata = new MetaData(); 
metadata.ID = Guid.NewGuid().ToString(); 
metadata.Created = DateTime.Now; 
metadata.Application = new schemasdev.local.tenant.Application(); 
metadata.Application.Name = "Publish Tenant"; 
metadata.Application.Core = ApplicationCore.PropertySystem; 
NewOperation newoperation = new NewOperation(); 
newoperation.Tenant = new Tenant(); 
newoperation.Tenant.Code = "001"; 
newoperation.Tenant.Name = "Mister X"; 

object request = type.GetConstructor(new Type[0]).Invoke(new object[0]); 

(request as TenantRequest).MetaData = metadata; 
(request as TenantRequest).New = newoperation; 

//Setting the schema location property 
type.InvokeMember("SchemaLocation", System.Reflection.BindingFlags.SetField, null, request, new object[] { "http://schemasdev.local/2012-01/Tenant/1.0/Tenant.xsd" }); 

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(type); 
stream = new System.IO.MemoryStream(); 
serializer.Serialize(stream, request); 

Console.WriteLine(UTF8Encoding.UTF8.GetString(stream.ToArray())); 

oluşturmak için kullanılan kod Ve sonunda mükemmel çıktı:

<?xml version="1.0"?> 
<TenantRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="http://schemasdev.local/2012-01/Tenant/1.0/Tenant.xsd" xmlns="http://schemasdev.local/2012-01/Tenant/1.0"> 
    <MetaData xmlns="http://schemasdev.local/2012-01/Messaging/1.0"> 
     <ID>b59938fd-8e68-4927-87da-6d92c609f159</ID> 
     <Application> 
      <Name>Publish Tenant</Name> 
      <Core>PropertySystem</Core> 
     </Application> 
     <Created>2012-02-20T10:07:54.645424+01:00</Created> 
    </MetaData> 
    <New> 
     <Tenant> 
      <Code>001</Code> 
      <Name>Mister X</Name> 
     </Tenant> 
    </New> 
</TenantRequest> 
3

yerine sınıfını değiştirerek

altına kodlama bakın schemaLocation özniteliğini eklemek için xsd.exe tarafından oluşturulan, sınıfı genişletebilir ve eski dosyalarınıza ekleyebilirsiniz. eğilimli sınıf.

orijinal şema MySchema.xsd denir Diyelim ve oluşturulan dosya adı MySchema.cs ve sınıf adı myschema olduğunu. İşte oluşturulan sınıf gibi görünebilir şudur: (.. Sınıf kısmi olduğunu unutmayın Bu onu uzatmak anlamına gelir)

[MySchema.cs]

namespace MyProgram.MySchemas { 
    using System.Xml.Serialization; 


    /// <remarks/> 
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")] 
    [System.SerializableAttribute()] 
    [System.Diagnostics.DebuggerStepThroughAttribute()] 
    [System.ComponentModel.DesignerCategoryAttribute("code")] 
    ... 
    public partial class MySchema { 

     private string someField; 

     ... 
     ... 
    } 
} 

yapmanız gerekenler Başka bir dosya oluştur, bu örnekte buna MySchemaExtender.cs diyeceğiz.

[MySchemaExtender: Bu dosya aynı sınıf adı myschema başka kısmi sınıf tanımını içerir.cs]

namespace MyProgram.MySchemas { 
    using System.Xml.Serialization; 

    public partial class MySchema {   
    } 
} 

Şimdi genişletilmiş sınıfında schemaLocation niteliğini konur tüm yapmanız gereken. Eğer herhangi bir şey değiştirmek zorunda kalmazsınız xsd.exe kullanarak sınıfı yeniden Şimdi eğer

[MySchemaExtender.cs]

namespace MyProgram.MySchemas { 
    using System.Xml.Serialization; 

    public partial class MySchema { 
     [XmlAttribute("schemaLocation", Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace)] 
     public string xsiSchemaLocation = @"http://someurl/myprogram http://someurl/myprogram/MySchema.xsd"; 
    } 
} 

: İşte son genişletilmiş sınıf nasıl görüneceğini olduğunu.

+0

Tam olarak - bu kabul edilen cevap olmalıdır. StyleCop gibi bir araç kullanırsanız, bu yaklaşım size bir uyarı verebilir, ancak örneğin kendi sahte yorum etiketinizi ekleyerek bunu kolayca yapabilirsiniz. –

İlgili konular