Ho parlato tempo fa di come comandare la serializzazione di una classe con XmlSerializer utilizzando XmlElementAttribute per avere il nome degli elementi XML non concorde con quello dei campi della Classe. In questi giorni mi è capitato di dover aggiungere degli attributi ai nodi del mio XML, e in questo caso le cose si complicano un poco ....

In particolare, l'oggetto da usre è XmlAttributeAttribute, che è un attributo con cui si possono decorare gli elementi di una classe nella stessa maniera di XmlElementAttribute che ho spiegato nel post precedente.

Il problema che ne deriva è che l'XmlAttribute aggiunge l'attributo al nodo corrente. Quindi, non possiamo metterlo nella gerarchia come se fosse un elemento normale, ma dobbiamo aggiungere un oggetto annidiato nel caso ci serva un attributo.

Mi spiego meglio, se avessi voluto un XML in uscita tipo

<PERSONE>
   <PERSONA>
       <NOME>Alessandro</NOME>
       <COGNOME>Ghizzardi</COGNOME>
   </PERSONA>
</PERSONE>

Avrei creato piu o meno queste classi:

[Serializable]
[XmlElement("PERSONE")]
public class Persone
{
   [XmlElement("PERSONA")]
   public PersoneCollection Persone;
}

[Serializable]
public class PersoneCollection : List<Persona>
{
}

[Serializable]
public class Persona
{
   [XmlElement("NOME")]
   public string Nome;
   [XmlElement("COGNOME")]
   public string Cognome;
}

Poniamo invece che l'XML debba avere degli attributi.

Se voglio aggiungere degli attributi in qualche nodo senza contenuto testo ho pochi problemi. Poniamo che voglia farlo diventare:

<PERSONE>
   <PERSONA Id="1">
       <NOME>Alessandro</NOME>
       <COGNOME>Ghizzardi</COGNOME>
   </PERSONA>
</PERSONE>

Basta aggiungere un elemento alla classe Persona e decorarlo con l'attributo corretto

[Serializable]
public class Persona
{
   [XmlAttribute("Id")]
   public int Id;
   [XmlElement("NOME")]
   public string Nome;
   [XmlElement("COGNOME")]
   public string Cognome;
}

perchè il nodo "PERSONA" non contiene testo ma solo elementi figli.
Se invece voglio aggiungere un attributo ad un elemento che contiene del testo, si complica un pò la faccenda.... Poniamo che voglia far diventare l'Xml in questo modo:

<PERSONE>
   <PERSONA>
       <NOME DaControllare="True">Alessandro</NOME>
       <COGNOME>Ghizzardi</COGNOME>
   </PERSONA>
</PERSONE>

Incontro dei problemi perchè "NOME" è il mapping di un oggetto Stringa, che come tale non può avere piu di un attributo legato. E se attacco un XmlAttribute alla stringa, questo andrà legato al nodo "PERSONA" non a "NOME" e poi non saprei come associarne il testo....

Quindi, devo modificare le mie classi aggiungendo un oggetto che si occupa di Renderizzare il nodo Nome. In questo mi viene in aiuto l'attributo XmlTextAttribute che "istruisce" l'oggetto a non utilizzare una stringa come nodo ma come testo.
Quindi il nostro esempio si tradurrebbe in:

[Serializable]
[XmlElement("PERSONE")]
public class Persone
{
   [XmlElement("PERSONA")]
   public PersoneCollection Persone;
}

[Serializable]
public class PersoneCollection : List<Persona>
{
}

[Serializable]
public class Persona
{
   [XmlElement("NOME")]
   public NomePersona Nome;
   [XmlElement("COGNOME")]
   public string Cognome;
}

[Serializable]
public class NomePersona
{
   [XmlAttribute("DaControllare")
   public bool DaControllare;
   [XmlText()]
   public string Text;
}

Notare che ora Persona.Nome non è piu una stringa ma un oggetto di tipo NomePersona che contiene l'attributo ed il testo, entrambi decorati con gli attributi specifici.
Perchè dovrei imbarcarmi in certe cose? Per il solito problema di parlare con Flash che, in troppi casi, si rivela poco agevole. Non per la tecnologia in se, ma per chi la usa :)