Как я могу переименовать имена классов через атрибуты Xml? - PullRequest
56 голосов
/ 06 сентября 2010

Предположим, у меня есть XML-сериализуемый класс с именем Песня :

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

Для экономии места (а также полуобфускация XML-файл), Я решил переименовать элементы xml:

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

Это приведет к выводу XML следующим образом:

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

Я также хочу переименовать / переназначить имя класса / объекта,Скажем, в приведенном выше примере я хочу переименовать класс Song в g .Чтобы результирующий xml выглядел так:

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

Можно ли переименовать имена классов с помощью атрибутов xml ?

Я не хочусоздать / пройти DOM вручную, поэтому мне было интересно, можно ли это сделать с помощью декоратора.

Заранее спасибо!

ОБНОВЛЕНИЕ: Упс!На этот раз я действительно сделал это снова!Забыл упомянуть - я на самом деле сериализую список объектов Song в XML.

Вот код сериализации:

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

А вот вывод 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>

Очевидно, атрибут XmlRoot () не переименовывает объект в контексте списка.

Я что-то упустил?

Ответы [ 5 ]

98 голосов
/ 11 марта 2011

Решение: используйте [XmlType (TypeName = "g")]

XmlRoot работает только с XML корневыми узлами согласно документации (и что выожидайте, учитывая, что его имя включает в себя root )!

Мне не удалось заставить работать другие ответы, поэтому продолжал копать ...

Вместо этого я обнаружил, что XmlTypeAttribute (то есть [XmlType]) и его свойство TypeName выполняют аналогичную работу для некорневых классов / объектов.

например,

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

Предполагается, что вы примените его к другим классам, например:

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

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

Это выведет следующее в точности так, как требуется в вопросе :

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

Я использовал это в нескольких производственных проектах и ​​не нашел никаких проблем с ним.

53 голосов
/ 06 сентября 2010

Проверьте атрибут XmlRoot.

Документация может быть найдена здесь: 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

ОБНОВЛЕНИЕ: Только что попробовал, и он отлично работает на VS 2008. Этот код:

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

Выходы:

<?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>
5 голосов
/ 06 сентября 2010

Если это корневой элемент документа, вы можете использовать [XmlRoot ("g")] .


Вот мой обновленный ответ, основанный на ваших разъяснениях. Степень контроля, о которой вы просите, невозможна без класса упаковки. В этом примере используется класс SongGroup для переноса списка, чтобы вы могли присваивать альтернативные имена элементам внутри.

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

У этого есть побочный эффект генерации еще одного внутреннего элемента, представляющего сам список. В моей системе вывод выглядит так:

<?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>
0 голосов
/ 06 сентября 2010

Использовать 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;
}

должно работать.

0 голосов
/ 06 сентября 2010
[XmlRoot("g")]
class Song
{
}

Должен сделать трюк

...