2017-12-18 6 views
1

DataContractSerializerとシリアル化しているIXmlSerializableを実装するタイプがあります。ルート要素の名前空間と名前をXML文書のルート要素として直列化する際に、どのように制御できますか?私は私が手に私のルートオブジェクトとしてDataContractSerializerでこれをシリアライズした場合データコントラクティブシリアライザを使用してIXmlSerializableオブジェクトをシリアル化するときに、ルート要素の名前空間と名前を制御するにはどうすればよいですか?

public partial class PersonDTO : IXmlSerializable 
{ 
    public string Name { get; set; } 

    #region IXmlSerializable Members 

    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(System.Xml.XmlReader reader) 
    { 
     Name = reader["name"]; 
     if (!reader.IsEmptyElement) 
      reader.Skip(); 
     reader.Read(); 
    } 

    public void WriteXml(System.Xml.XmlWriter writer) 
    { 
     writer.WriteAttributeString("name", Name); 
    } 

    #endregion 
} 

<PersonDTO name="John Doe" xmlns="http://schemas.datacontract.org/2004/07/MyClrNamespace" /> 

私はルート名が<Person>とルート名前空間にしたい

は、私は以下の型を持っていると言います"http://www.MyCompany.com"となるように、[DataContract]を追加してみました。

[DataContract(Name = "Person", Namespace = "http://www.MyCompany.com")] 
public partial class PersonDTO : IXmlSerializable 
{ 
} 

しかし、私はやるとき、DataContractSerializerタイプを述べ例外をスローは「PersonDTO」IXmlSerializableこととDataContractAttribute属性持つことはできません。私はDataContractSerializer(Type type, String rootName, String rootNamespace)コンストラクタを使用して、ルート名と名前空間を変更することが可能である知っている

System.Runtime.Serialization.InvalidDataContractException occurred 
    Message="Type 'PersonDTO' cannot be IXmlSerializable and have DataContractAttribute attribute." 
    Source="System.Runtime.Serialization" 
    StackTrace: 
     at System.Runtime.Serialization.XmlDataContract.XmlDataContractCriticalHelper..ctor(Type type) 
     at System.Runtime.Serialization.XmlDataContract..ctor(Type type) 
     at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type) 
     at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type) 
     at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode) 
     at System.Runtime.Serialization.DataContractSerializer.get_RootContract() 

を手動でシリアル化するとき:

var person = new PersonDTO { Name = "John Doe", }; 

var serializer = new DataContractSerializer(typeof(PersonDTO), "Person", @"http://www.MyCompany.com"); 
var sb = new StringBuilder(); 
using (var textWriter = new StringWriter(sb)) 
using (var xmlWriter = XmlWriter.Create(textWriter)) 
{ 
    serializer.WriteObject(xmlWriter, person); 
} 
Console.WriteLine(sb); 
// Outputs <Person name="John Doe" xmlns="http://www.MyCompany.com" /> 

ただし、属性を使用して自動的にこれを行う方法はありますか?

答えて

3

これは、2つの方法のいずれかで属性を使用して行うことができます。まず(そして驚くべきことに)

あなたは型に古いXmlSerializerため[XmlRoot]属性を適用する場合、DataContractSerializerは、ルートデータコントラクトの名前空間と名前として、その中に指定した名前空間と名前を使用します。

[XmlRoot("Person", Namespace = "http://www.MyCompany.com")] 
public partial class PersonDTO : IXmlSerializable 
{ 
} 

<Person name="John Doe" xmlns="http://www.MyCompany.com" /> 

ただし、この解決策はルート要素名にのみ適用されます。あなたは配列またはそのようなオブジェクトのジェネリックリスト未修正の名前空間と名前をシリアル化しようとした場合に使用されています

<ArrayOfPersonDTO xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyClrNamespace"> 
    <PersonDTO name="John Doe" /> 
</ArrayOfPersonDTO> 

第二、より力強く、[XmlSchemaProvider]属性は、データを返す静的メソッドを指定するために使用することができますコントラクト名、タイプのネームスペースとスキーマ:

[XmlSchemaProvider("GetSchemaMethod")] 
public partial class PersonDTO : IXmlSerializable 
{ 
    // This is the method named by the XmlSchemaProviderAttribute applied to the type. 
    public static XmlQualifiedName GetSchemaMethod(XmlSchemaSet xs) 
    { 
     // Fill in a plausible schema for the type if necessary. 
     // 
     // While DataContractSerializer will not use the returned schema set, 
     // svcutil.exe will use it to generate schemas. XmlSerializer also 
     // seems to require it to be initialized to something plausible if you 
     // are serializing your types with both serializers. 
     string personSchema = @"<xs:schema xmlns:tns=""http://www.MyCompany.com"" elementFormDefault=""qualified"" targetNamespace=""http://www.MyCompany.com"" xmlns:xs=""http://www.w3.org/2001/XMLSchema""> 
    <xs:element name=""Person"" nillable=""true"" type=""tns:Person"" /> 
    <xs:complexType name=""Person""> 
    <xs:attribute name=""name"" type=""xs:string"" /> 
    </xs:complexType> 
</xs:schema>"; 
     using (var textReader = new StringReader(personSchema)) 
     using (var schemaSetReader = System.Xml.XmlReader.Create(textReader)) 
     { 
      xs.Add("http://www.MyCompany.com", schemaSetReader); 
     } 
     // Return back the namespace and name to be used for this type. 
     return new XmlQualifiedName("Person", "http://www.MyCompany.com"); 
    } 
} 

これがしますルート名と名前空間が変更されるわけではありません唯一の利点を持っていますが、また配列、ジェネリックコレクション、およびその他のジェネリック医薬品に使用されるデータコントラクト名同様に:

<ArrayOfPerson xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.MyCompany.com"> 
    <Person name="John Doe" /> 
</ArrayOfPerson> 

注:

  • DataContractSerializerは、スキーマプロバイダーメソッドによって返されるだけXmlQualifiedNameを使用しています。ただし、svcutil.exeを使用してタイプのXSDを生成する場合、またはXmlSerializerを使用してタイプをシリアライズする場合は、XmlSchemaSet xsを入力する必要があります。 (そうすると、生成されたXSDに返されたスキーマが反映されます)。
関連する問題