2009-09-10 14 views
12

मैं xsd.exe इस्तेमाल किया GPX फाइलें लेखन/पढ़ने के लिए एक सी # वर्ग उत्पन्न करने के लिए। मैं xsi को शामिल करने के लिए परिणामस्वरूप XML फ़ाइल कैसे प्राप्त करूं: schemaLocation विशेषता उदाहरण के लिए। schemaLocation हमेशा याद आ रही हैXmlSerialization और 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> 

उत्तर

33

अपने उत्पन्न सी # वर्ग को यह करें::

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

जाहिर xsd.exe उपकरण does not generateschemaLocation विशेषता

मैं निम्नलिखित लेकिन xsi चाहते हैं।

+0

बिल्कुल सही धन्यवाद! –

+0

यह स्कीमा स्थान को कैसे सेट करेगा? जिस स्थान से XSD.EXE इसका उपयोग करता है वह वेब पर उपलब्ध होने की संभावना नहीं है, जहां 'xsi: schemaLocation' के उपयोगकर्ता को इसे ढूंढना होगा। –

+0

@ जॉन: शायद xsd फ़ाइल में मान निर्दिष्ट करने के लिए कुछ विकल्प है? – dtb

2

आपको इसे स्वयं करना होगा। एक्सएमएल सीरियलाइजेशन के बारे में जानने का कोई तरीका नहीं है कि आप अपनी स्कीमा किसी भी मामले में कहां जाना चाहते हैं।

हालांकि मैं इसे अभी तक परीक्षण नहीं किया यह प्रयास करें,:

[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
बेशक

इस उत्तर रास्ता बहुत देर हो चुकी है! लेकिन शायद अन्य डेवलपर्स के लिए उपयोगी ;-)। मैंने इस समस्या को हल करने के लिए पूर्णता का उपयोग किया, क्योंकि इसे स्वचालित होना था।

स्थिर विधि CreateMessageType बुलाया जाना चाहिए। serialized वर्ग होना चाहिए जिसमें schemaLocation संपत्ति नहीं है। यह विधि अभिभावक (नामित गतिशील) के रूप में उपयोग करके एक नया प्रकार लौटाती है, लेकिन स्कीमा स्थान गुण जोड़ें और XmlRootAttribute के ElementName प्रॉपर्टी को सेट करें।

प्रकार बनाने के बाद, प्रतिबिंब फिर वस्तु बना सकते हैं और गुणों को सेट करने के लिए इस्तेमाल किया जाना चाहिए।

कोड xxx में काफी दर्द की तरह दिखता है, लेकिन यह एक आकर्षण की तरह काम करता है!

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

निम्नलिखित कोड मैं वस्तु

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

बनाने के लिए इस्तेमाल और अंततः सही उत्पादन:

<?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

के बजाय वर्ग को संशोधित करने

नीचे कोडिंग देखें schemaLocation विशेषता जोड़ने के लिए xsd.exe द्वारा जेनरेट किया गया है, आप कक्षा का विस्तार कर सकते हैं और इसे अपने पूर्व में जोड़ सकते हैं श्रेणीबद्ध वर्ग

कहना मूल स्कीमा MySchema.xsd कहा जाता है की सुविधा देता है और उत्पन्न फ़ाइल नाम MySchema.cs है और वर्ग के नाम MySchema है।

क्या आप की जरूरत है

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

     ... 
     ... 
    } 
} 

: यहाँ क्या उत्पन्न वर्ग कैसा लग सकता है (ध्यान दें कि वर्ग आंशिक है इसका मतलब यह है कि हम इसे विस्तार कर सकते हैं।।) एक और फ़ाइल बनाएं, इस उदाहरण में हम इसे MySchemaExtender.cs कहते हैं।

[MySchemaExtender: यह फ़ाइल एक ही कक्षा नाम MySchema के साथ एक और आंशिक वर्ग परिभाषा में शामिल होंगे।सीएस]

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

    public partial class MySchema {   
    } 
} 

अब आपको विस्तारित कक्षा में schemaLocation विशेषता डालना है।

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

अब अगर आप का उपयोग कर आप कुछ भी संशोधित करने के लिए नहीं होगा xsd.exe वर्ग को पुनर्जीवित: यहाँ क्या अपने अंतिम विस्तारित वर्ग की तरह दिखाई देगा है।

+0

बिल्कुल - यह स्वीकार्य उत्तर होना चाहिए। यदि आप स्टाइलकॉप जैसे टूल का उपयोग करते हैं तो दृष्टिकोण आपको चेतावनी दे सकता है, लेकिन आप आसानी से इसके आसपास हो सकते हैं, उदाहरण के लिए अपना खुद का नकली टिप्पणी टैग जोड़कर। –

संबंधित मुद्दे