Как переименовать имена классов с помощью атрибутов Xml?
Предположим, что у меня есть 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>
Я хочу переименовать/переназначить имя класса/объекта. Скажем, в приведенном выше примере я хочу переименовать класс Песня в g. Чтобы получившийся xml выглядел так:
<g>
<a>Britney Spears</a>
<s>I Did It Again</s>
</g>
Можно ли переименовать имена классов через xml-attributes?
Я не хочу создавать/перемещать 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() не переименовывает объект в контексте списка.
Я что-то пропустил?
Ответы
Ответ 1
Оформить атрибут 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
UPDATE:
Просто попробовал, и он отлично работает на 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>
Ответ 2
Решение. Используйте [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>
Я использовал это в нескольких производственных проектах и не нашел с ним никаких проблем.
Ответ 3
Если это корневой элемент документа, вы можете использовать [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>
Ответ 4
[XmlRoot("g")]
class Song
{
}
Должен сделать трюк
Ответ 5
Использовать 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;
}
должен работать.