如何通过Xml属性重命名类名?


73

假设我有一个名为Song的可序列化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-attributes重命名类名?

我不想手动创建/遍历DOM,所以我想知道是否可以通过装饰器来实现。

提前致谢!

更新:糟糕!这次我真的又做了一次!忘了提及-我实际上是在XML中序列化Song对象的列表。

这是序列化代码:

    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()属性不会在列表上下文中重命名该对象。

我想念什么吗?


6
我认为XML中有错误。“我又做了一次”不是这首歌的正确标题。正确的标题是;“哎呀我再次做到了”。(只是为了防止验证者将来
遇到麻烦

3
仅供参考,[Serializable]与XML序列化无关。
约翰·桑德斯

根据您的澄清,请参阅我的最新回复。
bobbymcr 2010年

3
已经好几年了,所以更新正确答案可能是项:)当前标记为正确的答案对于所问问题实际上是不正确的(并且不会产生所需的输出)。 XmlTypeAttribute并且其TypeName属性是正确的方法(请参见下文)。
Gone Coding

@Ariel Popovsky:如果您检查编辑,即使问题的第一个版本也无法使用XmlRoot。OP已经存在两年了,因此它将继续误导各地的编码人员:)
Gone Coding

Answers:


61

签出XmlRoot属性。

可以在这里找到文档:http : //msdn.microsoft.com/zh-cn/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>

17
@Arial:遇到相同的问题,但是发现XmlRoot属性仅在我的根节点上有效(因为我猜应该基于文档)。不知道如何使上面的代码正常工作。使其与我的课程上的[XmlType(TypeName =“ newName”)]一起使用。
Gone Coding,

2
您松开<g> ... </ g>时,输出不正确,但这不能解决问题。解决方案是“ HiTech Magic” [XmlType(TypeName =“ g”)]的发布
Riccardo Bassilichi

@Ariel Popovsky,如果我希望Song是一个名为“ g”的元素,而Artist和SongTitle是该元素的属性该怎么办?IE,<sgr><sgs><g a="A1" s="S1" /><g a="A2" s="S2"><sgs><sgr>
–theB3RV

@ theB3RV使用[XmlAttribute(“ a”)]和[XmlAttribute(“ s”)]而不是XmlElement,您将获得属性而不是元素。要将Song从sgs重命名为g,只需在Songs列表XmlElement Attribute中更改ElementName。
Ariel Popovsky 2014年

3
XmlArrayItem("g")就是我一直在寻找
theB3RV

117

解决方案:使用[XmlType(TypeName =“ g”)]

XmlRoot只能使用XML的节点按照文档(和你所期望的,它的名字包括)!

我无法获得其他任何有效答案,所以一直在挖...

相反,我发现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>

我已经在多个生产项目中使用了它,但发现它没有问题。


它仍会输出<?xml version =“ 1.0” encoding =“ utf-16”?>
hakan

1
@piedpiper:取决于输出编码,XmlType此处不做描述。请问一个新的问题,如果您有一个:)
Gone Coding

5
这个答案比选择的答案好很多。
DotNet程序员

1
@DotNetProgrammer:不幸的是,OP多年没有上线,因此它一直停留在错误的答案上:)
Gone Coding

对于根节点,此解决方案不适用于我。接受的答案有效。
Codure

5

如果这是文档的根元素,则可以使用[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>

我意识到这是一个非常古老的问题/答案,但他们希望在特定的输出可用的XmlType(TypeName="g")]。您不需要包装类,而只需将类本身属性即可。干杯。
Gone Coding


-1
[XmlRoot("g")]
class Song
{
}

应该做的把戏


1
歌曲不是Root元素,因此这将不起作用。XmlRoot仅适用于根节点。抱歉。
Gone Coding
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.