Wie kann ich Klassennamen über XML-Attribute umbenennen?

73

Angenommen, ich habe eine XML-serialisierbare Klasse namens Song :

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

Um Platz zu sparen (und auch die XML-Datei halb zu verschleiern ), entscheide ich mich, die XML-Elemente umzubenennen:

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

Dadurch wird eine XML-Ausgabe wie folgt erzeugt:

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

Ich möchte auch den Namen der Klasse / des Objekts umbenennen / neu zuordnen. Angenommen, im obigen Beispiel möchte ich die Klasse Song in g umbenennen . Damit die resultierende XML folgendermaßen aussehen sollte:

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

Ist es möglich, Klassennamen über XML-Attribute umzubenennen ?

Ich möchte das DOM nicht manuell erstellen / durchlaufen, daher habe ich mich gefragt, ob dies über einen Dekorateur erreicht werden kann.

Danke im Voraus!

UPDATE: Ups! Diesmal habe ich es wirklich wieder getan! Ich habe vergessen zu erwähnen - ich serialisiere tatsächlich eine Liste von Song-Objekten im XML.

Hier ist der Serialisierungscode:

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

Und hier ist die XML-Ausgabe:

<?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>

Anscheinend benennt das XmlRoot () -Attribut das Objekt in einem Listenkontext nicht um.

Vermisse ich etwas

Invarbrass
quelle
6
Ich denke, es gibt einen Fehler in der XML. "Ich habe es wieder getan" ist nicht der richtige Titel des Songs. Der richtige Titel lautet; "Ups! ... ich habe es wieder getan". (Nur um zukünftige Frustrationen mit Validatoren zu verhindern)
Caspar Kleijne
3
Zu Ihrer Information, [Serializable]spielt für die XML-Serialisierung keine Rolle.
John Saunders
Siehe meine aktualisierte Antwort basierend auf Ihrer Klarstellung.
Bobbymcr
3
Es ist ein paar Jahre her, daher ist es möglicherweise sinnvoll, die richtige Antwort zu aktualisieren :) Die aktuell als richtig markierte Antwort ist für die gestellte Frage tatsächlich falsch (und führt nicht zur gewünschten Ausgabe). XmlTypeAttributeund seine TypeNameEigenschaft ist der richtige Weg, dies zu tun (siehe unten).
Gone Coding
@Ariel Popovsky: Wenn Sie die Änderungen überprüfen, hätte selbst die allererste Version der Frage nicht funktioniert XmlRoot. Das OP ist seit 2 Jahren nicht mehr hier, daher wird es weiterhin überall Codierer irreführen :)
Gone Coding

Antworten:

61

Überprüfen Sie das XmlRoot-Attribut.

Die Dokumentation finden Sie hier: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlrootattribute(v=VS.90).aspx

[XmlRoot(Namespace = "www.contoso.com", 
     ElementName = "MyGroupName", 
     DataType = "string", 
     IsNullable=true)]
public class Group

UPDATE: Gerade ausprobiert und es funktioniert perfekt auf VS 2008. Dieser Code:

[XmlRoot(ElementName = "sgr")]
public class SongGroup
{
    public SongGroup()
    {
       this.Songs = new List<Song>();
    }



[XmlElement(ElementName = "sgs")]
    public List<Song> Songs { get; set; }
}

[XmlRoot(ElementName = "g")]
public class Song
{
    [XmlElement("a")]
    public string Artist { get; set; }

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

Ausgänge:

<?xml version="1.0" encoding="utf-8"?>
<sgr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www
.w3.org/2001/XMLSchema">
  <sgs>
    <a>A1</a>
    <s>S1</s>
  </sgs>
  <sgs>
    <a>A2</a>
    <s>S2</s>
  </sgs>
</sgr>
Ariel Popovsky
quelle
17
@Arial: Hatte das gleiche Problem, fand aber heraus, dass das XmlRoot-Attribut nur auf meinem Stammknoten funktioniert (wie ich denke, sollte es auf den Dokumenten basieren). Ich bin mir nicht sicher, wie Sie den obigen Code dazu gebracht haben, richtig zu funktionieren. Ich habe es stattdessen für [XmlType (TypeName = "newName")] in meinen Klassen verwendet.
Gone Coding
2
Die Ausgabe ist nicht korrekt. Sie verlieren ein <g> ... </ g>, aber dies löst das Problem nicht. Die Lösung ist der Beitrag von "HiTech Magic" [XmlType (TypeName = "g")]
Riccardo Bassilichi
@Ariel Popovsky, was ist, wenn ich möchte, dass Song ein Element mit dem Namen "g" ist und Artist und SongTitle Attribute für dieses Element sind. IE,<sgr><sgs><g a="A1" s="S1" /><g a="A2" s="S2"><sgs><sgr>
theB3RV
@ theB3RV Verwenden Sie [XmlAttribute ("a")] und [XmlAttribute ("s")] anstelle von XmlElement, und Sie erhalten Attribute anstelle von Elementen. Um den Song von sgs in g umzubenennen, ändern Sie einfach den ElementName im XmlElement-Attribut der Songs-Liste.
Ariel Popovsky
3
XmlArrayItem("g")ist das, wonach ich gesucht habe
theB3RV
116

Lösung: Verwenden Sie [XmlType (TypeName = "g")]

XmlRoot funktioniert nur mit XML - Root - Knoten gemäß der Dokumentation (und was man erwarten würde, da sein Name beinhaltet root )!

Ich konnte keine der anderen Antworten auf die Arbeit bekommen, also grub ich weiter ...

Stattdessen stellte ich fest, dass das XmlTypeAttribute (dh [XmlType]) und seine TypeName- Eigenschaft einen ähnlichen Job für Nicht-Root- Klassen / Objekte ausführen .

z.B

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

Angenommen, Sie wenden es auf die anderen Klassen an, z.

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

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

Dadurch wird genau das ausgegeben , was in der Frage erforderlich ist :

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

Ich habe dies in mehreren Produktionsprojekten verwendet und keine Probleme damit festgestellt.

Codierung weg
quelle
es gibt immer noch <? xml version = "1.0" encoding = "utf-16"?> aus
hakan
1
@piedpiper: Das liegt an der Ausgabecodierung, nicht an der XmlTypehier beschriebenen. Bitte stellen Sie eine neue Frage, wenn Sie eine haben :)
Gone Coding
5
Diese Antwort funktioniert viel besser als die gewählte Antwort.
DotNet Programmer
1
@DotNetProgrammer: Leider ist das OP seit vielen Jahren nicht mehr online, so dass es bei einer falschen Antwort hängen bleibt :)
Gone Coding
Diese Lösung funktioniert bei mir für den Stammknoten nicht. Die akzeptierte Antwort funktioniert.
Codure
5

Wenn dies das Stammelement des Dokuments ist, können Sie [XmlRoot ("g")] verwenden .


Hier ist meine aktualisierte Antwort basierend auf Ihrer Klarstellung. Der Grad der Kontrolle, den Sie verlangen, ist ohne eine Wrapping-Klasse nicht möglich. In diesem Beispiel wird SongGroupdie Liste mit einer Klasse umbrochen, sodass Sie den darin enthaltenen Elementen alternative Namen geben können.

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

Dies hat den Nebeneffekt, dass ein weiteres inneres Element erzeugt wird, das die Liste selbst darstellt. Auf meinem System sieht die Ausgabe folgendermaßen aus:

<?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>
bobbymcr
quelle
Mir ist klar, dass dies eine sehr alte Frage / Antwort ist, aber die spezifische Ausgabe, die sie wollten, ist mit verfügbar XmlType(TypeName="g")]. Sie benötigen keine Wrapping-Klasse und können die Klassen einfach selbst zuordnen. Prost.
Gone Coding
-1
[XmlRoot("g")]
class Song
{
}

Sollte den Trick machen

Raj
quelle
1
Song ist nicht das Root-Element, daher funktioniert dies nicht. XmlRoot gilt nur für den Stammknoten. Es tut uns leid.
Gone Coding