2009-02-26 1 views
14

Если у меня есть класс, отмеченный как DataContract и несколько свойств на ней отмечены DataMember атрибутов я могу сериализовать его в XML легко, но это создало бы вывод, как:Как вы можете контролировать сериализацию .NET DataContract, чтобы вместо XML использовать атрибуты XML?

<Person> 
    <Name>John Smith</Name> 
    <Email>[email protected]</Email> 
    <Phone>123-123-1234</Phone> 
</Person> 

То, что я предпочел бы это атрибуты , как ...

<Person Name="John Smith" Email="[email protected]" Phone="123-123-1234" /> 

атрибут DataMember позволяет мне контролировать имя и порядок, но не является ли сериализовать в качестве элемента или атрибута. Я огляделся и нашел DataContractFormat и IXmlSerializable, но я надеюсь, что там есть более простое решение.

Что такое самый простой способ сделать это?

+0

Кроме того, мне нужен XML, чтобы работать таким образом, в то время как JSON продолжает работать. – Brennan

ответ

11

Вы не можете сделать это с помощью DataContractSerializer; если вам нужны атрибуты, вам нужно использовать XmlSerializer. С классом DataContractSerializer разрешено более ограничительное подмножество спецификации XML, что повышает производительность и улучшает взаимодействие опубликованных сервисов, но дает вам более ограниченный контроль над XML-форматом.

Если вы используете службы WCF, взгляните на XmlSerializerFormatAttribute, что позволяет использовать сериализацию XmlSerializer.

+1

Должен быть простой способ использовать атрибуты. Я не забочусь о веб-сервисах, я просто выводил XML в определенном формате. – Brennan

+0

Привет, я, боюсь, что Грег прав - см. Http://msdn.microsoft.com/en-us/library/ms731923.aspx для ограничений DataContractSerializer. – larsw

+1

Если вы не заботитесь о веб-сервисах, то почему вы используете WCF? Вы просто пытаетесь сериализовать некоторые классы? Если это так, используйте сам XmlSerializer. –

34

Вы можете сделать это с DataContractSerializer - ответ взять на Xml сериализации себя, реализуя IXmlSerializable интерфейс . Для только для записи поддержки - вы можете оставить реализацию ReadXml пустой и возвращение нуль для GetSchema, а затем написать реализацию WriteXml следующим образом:

public class MyPerson : IXmlSerializable 
{ 
    public string Name { get; set;} 
    public string Email { get; set;} 
    public string Phone { get; set;} 

    public XmlSchema GetSchema() { return null; } 
    public void ReadXml(XmlReader reader) { } 
    public void WriteXml(XmlWriter writer) 
    { 
    writer.WriteAttributeString("name", Name); 
    writer.WriteAttributeString("email", Email); 
    writer.WriteAttributeString("phone", Phone); 
    } 
} 

Если вы используете тот же введите, например, сериализацию JSON, тогда вы по-прежнему можете добавлять атрибуты DataContract и DataMember - DataContractSerializer будет использовать реализацию интерфейса IXmlSerializable только при написании Xml.

Я писал об этом here.

+0

Вы уверены, что 'DataContractSerializer' будет вызывать метод WriteXml этого кода? –

+1

Я знаю - кажется маловероятным - но я только что опубликовал статью в нашем корпоративном блоге по адресу http: //www.labs.jobserve.com/Articles.aspx/Building-Labs - Writing-a-OpenSearch-Suggestions-provider-in-C-with-WCF, где вы можете загрузить исходный код, который показывает его в действии (используя его для реализации предложений OpenSearch). Этот ключ появился из этого содержимого MSDN: http://msdn.microsoft.com/en-us/library/ms731923.aspx. –

+0

Также не забудьте ознакомиться с http://msdn.microsoft.com/en-us/library/aa347876.aspx. –

0

Вы можете конвертировать назад и вперед между атрибутами и элементами при сериализации/десериализации. Следующие работы для последнего.

private XmlReader AttributesToElements(Stream stream) 
    { 
      var root = XElement.Load(stream); 
      foreach (var element in root.Descendants()) { 
        foreach (var attribute in element.Attributes()) 
          element.Add(new XElement(root.Name.Namespace + attribute.Name.LocalName, (string)attribute)); 
        element.Attributes().Remove(); 
      } 
      return root.CreateReader(); 
    }