2017-12-18 2 views
1

DataContractSerializer으로 직렬화하는 IXmlSerializable을 구현하는 유형이 있습니다. 그것을 XML 문서의 루트 요소로 직렬화 할 때 루트 요소 네임 스페이스와 이름을 어떻게 제어 할 수 있습니까? 루트 네임 스페이스를데이터 계약자 직렬화기를 사용하여 IXmlSerializable 객체를 직렬화 할 때 루트 요소 네임 스페이스와 이름을 제어하는 ​​방법은 무엇입니까?

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

내가 루트 이름 <Person>로 원하는 : 내 루트 개체 내가 얻을로 DataContractSerializer으로이 직렬화 경우

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 
} 

:

나는 다음과 같은 유형이 말 "http://www.MyCompany.com"이되도록 을 다음과 같이 추가하려고 시도했습니다.

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

그러나 내가 할 때, DataContractSerializer종류라는 예외를 throw는 '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

두 가지 방법 중 하나로 속성을 사용하여 수행 할 수 있습니다.

첫째 (의외로) 당신이 유형에 이전 XmlSerializer[XmlRoot] 특성을 적용 할 경우, DataContractSerializer 루트 데이터 계약의 네임 스페이스와 이름으로 거기에 지정된 네임 스페이스와 이름을 사용합니다 :

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

을 다음 XML을 생성합니다.

<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에 반환 된 스키마가 반영됩니다.)
관련 문제