it-swarm.dev

Come posso rinominare i nomi di classe tramite gli attributi Xml?

Supponiamo che io abbia una classe serializzabile XML chiamata Song:

[Serializable]
class Song
{
    public string Artist;
    public string SongTitle;
}

Per risparmiare spazio (e anche semi-offuscato il file XML), decido di rinominare gli elementi xml:

[XmlRoot("g")]
class Song
{
    [XmlElement("a")]
    public string Artist;
    [XmlElement("s")]
    public string SongTitle;
}

Questo produrrà un output XML in questo modo:

<Song>
  <a>Britney Spears</a>
  <s>I Did It Again</s>
</Song>

Voglio rinominare/rimappare anche il nome della classe/oggetto. Ad esempio, nell'esempio sopra, desidero rinominare la classe Song in g. In modo che l'xml risultante dovrebbe apparire così:

<g>
  <a>Britney Spears</a>
  <s>I Did It Again</s>
</g>

È possibile rinominare i nomi di classe tramite attributi xml?

Non desidero creare/attraversare manualmente il DOM, quindi mi chiedevo se potesse essere realizzato tramite un decoratore.

Grazie in anticipo!

AGGIORNAMENTO: Oops! Questa volta ho davvero fatto di nuovo! Ho dimenticato di menzionare - In realtà sto serializzando un elenco di oggetti Song nell'XML.

Ecco il codice di serializzazione:

    public static bool SaveSongs(List<Song> songs)
    {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Song>));
            using (TextWriter textWriter = new StreamWriter("filename"))
            {
                serializer.Serialize(textWriter, songs);
            }
    }

Ed ecco l'output XML:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSong>
<Song>
  <a>Britney Spears</a>
  <s>Oops! I Did It Again</s>
</Song>
<Song>
  <a>Rihanna</a>
  <s>A Girl Like Me</s>
</Song>
</ArrayOfSong>

Apparentemente, l'attributo XmlRoot () non rinomina l'oggetto in un contesto di elenco.

Mi sto perdendo qualcosa?

59
invarbrass

Soluzione: utilizzare [XmlType (TypeName = "g")]

XmlRoot funziona solo con XML root nodi come da documentazione (e cosa ti aspetteresti, dato che il suo nome include root )!

Non sono riuscito a ottenere nessuna delle altre risposte al lavoro, quindi ho continuato a scavare ...

Invece ho scoperto che il XmlTypeAttribute (ovvero [XmlType]) e la sua proprietà TypeName svolgono un lavoro simile per non root classi/oggetti.

per esempio.

[XmlType(TypeName="g")]
class Song
{
    public string Artist;
    public string SongTitle;
}

Supponendo di applicarlo alle altre classi, ad es .:

[XmlType(TypeName="a")]
class Artist
{
    .....
}

[XmlType(TypeName="s")]
class SongTitle
{
    .....
}

Questo produrrà il seguente esattamente come richiesto nella domanda :

<g>
  <a>Britney Spears</a>
  <s>I Did It Again</s>
</g>

L'ho usato in diversi progetti di produzione e non ho riscontrato alcun problema.

101
Gone Coding

Se questo è l'elemento radice del documento, puoi usare [XmlRoot ("g")] .


Ecco la mia risposta aggiornata basata sul tuo chiarimento. Il grado di controllo richiesto non è possibile senza una classe di wrapping. In questo esempio viene utilizzata una classe SongGroup per racchiudere l'elenco in modo da poter assegnare nomi alternativi agli elementi all'interno.

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

public class SongGroup
{
    public SongGroup()
    {
        this.Songs = new List<Song>();
    }

    [XmlArrayItem("g", typeof(Song))]
    public List<Song> Songs { get; set; }
}

public class Song 
{ 
    public Song()
    {
    }

    [XmlElement("a")] 
    public string Artist { get; set; }

    [XmlElement("s")]
    public string SongTitle { get; set; }
} 

internal class Test
{
    private static void Main()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(SongGroup));

        SongGroup group = new SongGroup();
        group.Songs.Add(new Song() { Artist = "A1", SongTitle = "S1" });
        group.Songs.Add(new Song() { Artist = "A2", SongTitle = "S2" });

        using (Stream stream = new MemoryStream())
        using (StreamWriter writer = new StreamWriter(stream))
        {
            serializer.Serialize(writer, group);
            stream.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(stream))
            {
                Console.WriteLine(reader.ReadToEnd());
            }
        }
    }
}

Ciò ha l'effetto collaterale di generare un altro elemento interno che rappresenta l'elenco stesso. Sul mio sistema, l'output è simile al seguente:

<?xml version="1.0" encoding="utf-8"?>
<SongGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Songs>
    <g>
      <a>A1</a>
      <s>S1</s>
    </g>
    <g>
      <a>A2</a>
      <s>S2</s>
    </g>
  </Songs>
</SongGroup>
5
bobbymcr
[XmlRoot("g")]
class Song
{
}

Dovrebbe fare il trucco

0
Raj

Usa XmlElementAttribute: http://msdn.Microsoft.com/en-us/library/system.xml.serialization.xmlrootattribute.aspx

[Serializable]
[XmlRoot(ElementName="g")]
class Song
{
    public string Artist;
    public string SongTitle;
}

dovrebbe funzionare.

0