2009-02-26 5 views
14

Si j'ai une classe marquée comme DataContract et quelques propriétés sur ce que je peux sérialiser marqués par DataMember attributs vers XML facilement, mais ce serait créer une sortie comme:Comment pouvez-vous contrôler la sérialisation de .NET DataContract pour qu'elle utilise des attributs XML au lieu d'éléments?

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

Ce que je préférerais est des attributs , comme ...

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

l'attribut DataMember me permet de contrôler le nom et l'ordre, mais pas si elle est sérialisé comme un élément ou un attribut. J'ai regardé autour et trouvé DataContractFormat et IXmlSerializable mais j'espère qu'il y a là une solution plus facile.

Quelle est la manière la plus simple de le faire?

+0

De plus, j'ai besoin du XML pour fonctionner de cette façon pendant que JSON continue de fonctionner. – Brennan

Répondre

11

Vous ne pouvez pas faire cela avec le DataContractSerializer; Si vous voulez des attributs, vous devez utiliser le XmlSerializer à la place. Avec la classe DataContractSerializer, un sous-ensemble plus restrictif de la spécification XML est autorisé, ce qui améliore les performances et améliore l'interopérabilité des services publiés, mais vous donne moins de contrôle sur le format XML.

Si vous utilisez les services WCF, jetez un coup d'œil à XmlSerializerFormatAttribute, ce qui vous permet d'utiliser le XmlSerializer pour la sérialisation.

+1

Il doit y avoir un moyen simple de le faire utiliser des attributs. Je ne me soucie pas des services web, je ne fais que sortir le XML dans un format spécifique. – Brennan

+0

Bonjour, j'ai peur que Greg ait raison - voir http://msdn.microsoft.com/en-us/library/ms731923.aspx pour les limitations de DataContractSerializer. – larsw

+1

Si vous ne vous souciez pas des services Web, pourquoi utilisez-vous WCF? Essayez-vous juste de sérialiser certaines classes? Si c'est le cas, utilisez XmlSerializer par lui-même. –

34

Vous pouvez le faire avec le DataContractSerializer - la réponse est de prendre en charge la sérialisation Xml vous en mettant en œuvre la Interface IXmlSerializable. Pour support en écriture seule - vous pouvez laisser la mise en œuvre de WriteXml comme suit mise en œuvre de ReadXml vide et return null pour GetSchema, puis écrire:

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

Si vous utilisez le même tapez, par exemple, la sérialisation JSON, puis vous êtes toujours libre d'ajouter les attributs DataContract et DataMember - DataContractSerializer utilisera l'implémentation de l'interface IXmlSerializable uniquement lors de l'écriture de Xml.

J'ai blogué à ce sujet here.

+0

Etes-vous certain que 'DataContractSerializer' va appeler la méthode' WriteXml' de ce code? –

+1

Je sais - cela semble peu probable - mais je viens de poster un article sur notre blog d'entreprise à http: //www.labs.jobserve.com/Articles.aspx/Building-Labs - Ecriture-un-OpenSearch-Suggestions-fournisseur-dans-C-avec-WCF où vous pouvez télécharger le code source qui le montre en action (en l'utilisant pour implémenter des suggestions OpenSearch). L'indice provient de ce contenu MSDN: http://msdn.microsoft.com/en-us/library/ms731923.aspx. –

+0

Assurez-vous également de voir http://msdn.microsoft.com/en-us/library/aa347876.aspx. –

0

Vous pouvez effectuer des conversions entre les attributs et les éléments lors de la sérialisation/désérialisation. Les travaux suivants pour ce dernier.

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(); 
    } 
Questions connexes