2009-02-26 11 views
14

Se ho una classe contrassegnata come una DataContract e alcune proprietà su di esso contrassegnati con DataMember attributi posso serializzare fuori per XML facilmente, ma vorrei creare un output simile:Come è possibile controllare la serializzazione .NET DataContract in modo che utilizzi attributi XML anziché elementi?

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

Quello che preferirei è attributi , come ...

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

l'attributo DataMember mi permette di controllare il nome e l'ordine, ma non se è serializzato come un elemento o attributo. Mi sono guardato intorno e ho trovato DataContractFormat e IXmlSerializable ma spero che ci sia una soluzione più semplice.

Qual è il modo più semplice per farlo?

+0

Inoltre, ho bisogno che l'XML funzioni in questo modo mentre JSON continua a funzionare. – Brennan

risposta

11

Non è possibile farlo con DataContractSerializer; se vuoi attributi devi invece usare lo XmlSerializer. Con la classe DataContractSerializer è consentito un sottoinsieme più restrittivo della specifica XML che migliora le prestazioni e migliora l'interoperabilità dei servizi pubblicati, ma offre un controllo piuttosto limitato sul formato XML.

Se si utilizzano i servizi WCF, consultare XmlSerializerFormatAttribute che consente di utilizzare lo XmlSerializer per la serializzazione.

+1

Deve esserci un modo semplice per farlo usare attributi. Non mi preoccupo dei servizi Web, ma solo dell'output dell'XML in un formato specifico. – Brennan

+0

Salve, I ', ho paura che Greg sia corretto: vedere http://msdn.microsoft.com/en-us/library/ms731923.aspx per le limitazioni di DataContractSerializer. – larsw

+1

Se non ti preoccupi dei servizi web, allora perché stai usando WCF? Stai solo cercando di serializzare alcune classi? In tal caso, utilizzare XmlSerializer da solo. –

34

si può fare questo con il DataContractSerializer - la risposta è di prendere in consegna la serializzazione XML te implementando l'interfaccia IXmlSerializable . Per sola scrittura supporto - è possibile lasciare la attuazione ReadXml vuota, e ritorno nullo per GetSchema, e poi scrivere la realizzazione di WriteXml come segue:

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

se si sta utilizzando lo stesso digita anche per la serializzazione JSON, quindi sei ancora libero di aggiungere gli attributi DataContract e DataMember: DataContractSerializer utilizzerà l'implementazione dell'interfaccia IXmlSerializable solo durante la scrittura di Xml.

Ho bloggato su questo here.

+0

Sei sicuro che 'DataContractSerializer' invocherà il metodo' WriteXml' di questo codice? –

+1

Lo so - sembra improbabile - ma ho appena pubblicato un articolo sul nostro blog aziendale all'indirizzo http: //www.labs.jobserve.it/Articles.aspx/Building-Labs - Writing-an-OpenSearch-Suggestions-provider-in-C-with-WCF in cui è possibile scaricare il codice sorgente che lo mostra in azione (utilizzandolo per implementare i suggerimenti di OpenSearch). L'indizio è venuto da questo contenuto MSDN: http://msdn.microsoft.com/en-us/library/ms731923.aspx. –

+0

Inoltre, assicurarsi di vedere http://msdn.microsoft.com/en-us/library/aa347876.aspx. –

0

È possibile convertire avanti e indietro tra attributi ed elementi durante la serializzazione/deserializzazione. I seguenti lavori per quest'ultimo.

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(); 
    } 
Problemi correlati