2012-07-04 21 views
39

ho la seguente classe:Serialize proprietà come XML attributo in elemento

[Serializable] 
public class SomeModel 
{ 
    [XmlElement("SomeStringElementName")] 
    public string SomeString { get; set; } 

    [XmlElement("SomeInfoElementName")] 
    public int SomeInfo { get; set; } 
} 

che (quando popolato con alcuni dati di prova) e serializzati mediante XmlSerializer.Serialize() genera il seguente XML:

<SomeModel> 
    <SomeStringElementName>testData</SomeStringElementName> 
    <SomeInfoElementName>5</SomeInfoElementName> 
</SomeModel> 

Quello che dovete avere è:

<SomeModel> 
    <SomeStringElementName Value="testData" /> 
    <SomeInfoElementName Value="5" /> 
</SomeModel> 

c'è un modo per specificare questo come attributi ingegno stai scrivendo il mio codice di serializzazione personalizzato?

risposta

65

Avrete bisogno di classi wrapper:

public class SomeIntInfo 
{ 
    [XmlAttribute] 
    public int Value { get; set; } 
} 

public class SomeStringInfo 
{ 
    [XmlAttribute] 
    public string Value { get; set; } 
} 

public class SomeModel 
{ 
    [XmlElement("SomeStringElementName")] 
    public SomeStringInfo SomeString { get; set; } 

    [XmlElement("SomeInfoElementName")] 
    public SomeIntInfo SomeInfo { get; set; } 
} 

o un approccio più generico, se si preferisce:

public class SomeInfo<T> 
{ 
    [XmlAttribute] 
    public T Value { get; set; } 
} 

public class SomeModel 
{ 
    [XmlElement("SomeStringElementName")] 
    public SomeInfo<string> SomeString { get; set; } 

    [XmlElement("SomeInfoElementName")] 
    public SomeInfo<int> SomeInfo { get; set; } 
} 

E poi:

class Program 
{ 
    static void Main() 
    { 
     var model = new SomeModel 
     { 
      SomeString = new SomeInfo<string> { Value = "testData" }, 
      SomeInfo = new SomeInfo<int> { Value = 5 } 
     }; 
     var serializer = new XmlSerializer(model.GetType()); 
     serializer.Serialize(Console.Out, model); 
    } 
} 

produrrà:

<?xml version="1.0" encoding="ibm850"?> 
<SomeModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <SomeStringElementName Value="testData" /> 
    <SomeInfoElementName Value="5" /> 
</SomeModel> 
+3

Sì, che mi dà lo schema XML ho bisogno ma aggiunge un livello di indirezione inutile e la complessità del modello. Ora invece di Object.SomeProperty, ho Object.SomeProperty.Value. Mi rendo conto che potrei non essere in grado di utilizzarlo in entrambi i modi usando la serializzazione integrata, ma questa è l'essenza della domanda. – IUnknown

+2

Ecco come funziona il serializzatore integrato. –

+0

So che questo è un po 'vecchio, ma vorrei aggiungere operazioni implicita del cast da 'T' a' 'SomeInfo e viceversa. – Shago

3

In genere, utilizzare XmlAttribute anziché XmlElement, ma non assomiglia a quello che si desidera. Sarà simile al seguente:

<SomeModel SomeStringElementName="testData"> 
</SomeModel> 

L'unico modo che posso pensare di ottenere ciò che si vuole (nativamente) sarebbe quello di avere proprietà che punta a oggetti con nome SomeStringElementName e SomeInfoElementName dove la classe conteneva un singolo getter denominata " valore". Si potrebbe fare un ulteriore passo avanti e utilizzare DataContractSerializer in modo che le classi wrapper possano essere private. XmlSerializer non leggerà le proprietà private.

// TODO: make the class generic so that an int or string can be used. 
[Serializable] 
public class SerializationClass 
{ 
    public SerializationClass(string value) 
    { 
     this.Value = value; 
    } 

    [XmlAttribute("value")] 
    public string Value { get; } 
} 


[Serializable]      
public class SomeModel      
{      
    [XmlIgnore]      
    public string SomeString { get; set; }      

    [XmlIgnore]      
    public int SomeInfo { get; set; } 

    [XmlElement] 
    public SerializationClass SomeStringElementName 
    { 
     get { return new SerializationClass(this.SomeString); } 
    }    
} 
+0

Hey Chris, Sì, ho potuto usare XmlAttribute ma come lei ha detto che non darà il risultato che mi serve. Speravo di essere in grado di ottenere ciò di cui avevo bisogno senza scrivere il mio codice di serializzazione. – IUnknown

+0

@IUnknown - ho buttato insieme uno forse modo per raggiungere ciò che si desidera. Non è bello, creare classi per ottenere un nodo, quindi se qualcun altro sa di un modo migliore, sarei interessato pure. –

Problemi correlati