XmlSerializer 列表项元素名称
我有一个类 PersonList
[XmlRoot("Persons")]
PersonList : List<Human>
当我将其序列化为 XML 时,默认情况下它会生成如下内容:
<Persons>
<Human>...</Human>
<Human>...</Human>
</Persons>
我的问题是需要做什么才能将元素 Human
更改为输出中的 Person
?所以输出将是:
<Persons>
<Person>...</Person>
<Person>...</Person>
</Persons>
并且,如何将上述 XML 反序列化为 PersonList
类对象?
根据尼克的建议,这是我的测试代码:
[XmlRoot("Persons")]
public class Persons : List<Human>
{
}
[XmlRoot("Person")]
public class Human
{
public Human()
{
}
public Human(string name)
{
Name = name;
}
[XmlElement("Name")]
public string Name { get; set; }
}
void TestXmlSerialize()
{
Persons personList = new Persons();
personList.Add(new Human("John"));
personList.Add(new Human("Peter"));
try
{
using (StringWriter writer = new StringWriter())
{
XmlSerializer serializer = new XmlSerializer(typeof(Persons));
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
serializer.Serialize(xmlWriter, personList, namespaces);
Console.Out.WriteLine(writer.ToString());
}
}
catch (Exception e)
{
Console.Out.WriteLine( e.ToString());
}
}
测试代码的输出是:
<Persons>
<Human>
<Name>John</Name>
</Human>
<Human>
<Name>Peter</Name>
</Human>
</Persons>
如输出所示,Human
上的 [XmlRoot("Person")]
不将标签从 Human
更改为 Person
。
I have a class PersonList
[XmlRoot("Persons")]
PersonList : List<Human>
when I serialize this to XML, by default it will produce something like this:
<Persons>
<Human>...</Human>
<Human>...</Human>
</Persons>
My question is what needs to be done in order to change element Human
to Person
in the output? so the output would be :
<Persons>
<Person>...</Person>
<Person>...</Person>
</Persons>
and, how to deserialize the above XML to the PersonList
class object?
Per Nick's advice, Here is my testing code:
[XmlRoot("Persons")]
public class Persons : List<Human>
{
}
[XmlRoot("Person")]
public class Human
{
public Human()
{
}
public Human(string name)
{
Name = name;
}
[XmlElement("Name")]
public string Name { get; set; }
}
void TestXmlSerialize()
{
Persons personList = new Persons();
personList.Add(new Human("John"));
personList.Add(new Human("Peter"));
try
{
using (StringWriter writer = new StringWriter())
{
XmlSerializer serializer = new XmlSerializer(typeof(Persons));
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
XmlWriter xmlWriter = XmlWriter.Create(writer, settings);
serializer.Serialize(xmlWriter, personList, namespaces);
Console.Out.WriteLine(writer.ToString());
}
}
catch (Exception e)
{
Console.Out.WriteLine( e.ToString());
}
}
The output of the testing code is:
<Persons>
<Human>
<Name>John</Name>
</Human>
<Human>
<Name>Peter</Name>
</Human>
</Persons>
As the output shows, the [XmlRoot("Person")]
on Human
does not change the tag to Person
from Human
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
使用以下属性标记您的类:
XmlType 属性将导致 OP 中请求的输出。根据文档 :
Mark your class with the following attributes:
The XmlType attribute will result in the output requested in the OP. Per the documentation:
我认为您没有办法控制生成的数组元素的名称。
但是,如果您可以将
Persons
集合包装在另一个类中,那么您将可以使用XmlArrayAttribute
和XmlArrayItemAttribute
完全控制生成的输出。如果您无法创建这个新类,您可以求助于实现
IXmlSerialized
,但这要复杂得多。第一种选择的示例如下:
I don't think there is a way for you to control the name of the generated array elements.
If you can however wrap the
Persons
collection inside another class you will then have complete control over the generated output usingXmlArrayAttribute
andXmlArrayItemAttribute
.If you cannot create this new class you can resort to implementing
IXmlSerializable
, but this is much more complex.An example for the first alternative follows:
我的序列化器也遇到了同样的问题。上面的答案都没有完全起作用。我发现 Human 类上的 XmlRoot 属性明显被忽略,因为它不是文档的根元素。将列表包装在上下文对象中对我来说不是一个选择,因为我无法更改 XML 架构。解决方案是更改 Persons 类。您可以将通用列表包装在一个对象中并更改其序列化方式,而不是对通用列表进行子类化。请参阅下面的示例代码:
使用 XmlElement 序列化通用列表意味着它不会像 XmlArray 或子类化那样将包装器元素放在列表周围。它还为您提供了向 Persons 类添加属性的额外选项,这就是我的想法的来源:
如何向 XmlArray 元素添加属性(XML 序列化)?
I had the identical problem with my serializer. None of the answers above worked exactly. I found that the XmlRoot attribute on the Human class is plainly ignored because it isn't the root element of the document. Wrapping the list in a context object wasn't an option for me because I can't change the XML schema. The solution is to change up the Persons class. Instead of subclassing a generic list, you wrap it in an object and change how it is serialized. See the sample code below:
Serializing your generic list using XmlElement means that it won't put the wrapper element around your list like XmlArray does or like the subclassing does. It also gives you the bonus option of adding attributes to the Persons class, which is where I got the idea from:
How do I add a attribute to a XmlArray element (XML Serialization)?
这是我的测试代码
和运行程序
这也是结果
This is mine test code
and running program
Also this is the result
将 Human 上的
XmlRoot
设置为:Sidebar:
Persons 可能应该是 People
Set the
XmlRoot
on Human to:Sidebar:
Persons should probably be People
还有另一种选择。您始终可以在集合(以及任何其他类或结构)中实现 IXmlSerialized,以完全控制项目的写入或读取方式。你们中的许多人已经知道,当然,它通常不是首选,因为您最终可能会手动编写“样板”代码,这实际上应该是使用属性指定的自动逻辑。
对于必须匹配合理模式的集合来说,这是合理的。因为框架在这里有一个硬限制,并且如果正确完成,现有项目类型的序列化代码不必重复;即不要在集合代码中重写项目序列化,只需在 ReadXml/WriteXml 实现中创建/调用子 XmlSerializer。
使用 IXmlSerialized 的后果是它不允许您应用 XmlTypeAttribute(引发运行时错误,告诉您只能使用 XmlRootAttribute)。因此,请改为应用 XmlSchemaProviderAttribute 并返回您在 XmlTypeAttribute 中放入的相同限定名称。旧的 GetSchema 方法无论如何都应该返回 null,因为它只是一个保留方法(根据 MSDN),可能是因为他们忘记包含指定不同名称空间的功能。就我个人而言,我在 XmlSchemaProviderAttribute 中使用相同的“GetSchema”方法名称,因此它在旧占位符 GetSchema 方法旁边显示为完全覆盖。
当然,最好的解决方案是 Microsoft 允许我们将 XmlArrayItemAttribute 应用于集合/列表类并在 XmlSerializer 中使用它。默认情况下,它在集合中使用 XML 类型元素名称,我认为这是一个错误,因为指定时它应该是 XML 根名称,未指定时它应该是类名称。
当我有时间时,我会回来添加一个例子。现在看一下 IXmlSerialized 和 XmlSchemaProviderAttribute 的 MSDN 文档示例。
http://msdn .microsoft.com/en-us/library/system.xml.serialization.ixmlserialized(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlschemaproviderattribute( v=vs.110).aspx
There is another alternative. You can always implement IXmlSerializable in collections (and any other class or struct) to fully control how items are written or read. Many of you will know that already, it's not generally preferred of course as you may end-up writing out "boiler-plate" code by hand which should really be automatic logic specified with attributes.
For collections which must match a sensible schema it's justifiable. Because the framework has a hard limitation here and the existing item type's serialization code does not have to be duplicated when done properly; i.e. Do not re-write the item serialization in the collection code, just create/call a child XmlSerializer inside your ReadXml/WriteXml implementation.
Once consequence of using IXmlSerializable is it does not allow you to apply the XmlTypeAttribute (throws a runtime error telling you only XmlRootAttribute may be used). So instead apply the XmlSchemaProviderAttribute and return the same qualified name you would have put in the XmlTypeAttribute. The old GetSchema method should return null anyway as it was only a reserved method (according to MSDN), probably because they forgot to include the ability to specify a different namespace. Personally I use the same "GetSchema" method name in my XmlSchemaProviderAttribute so it appears as a complete override next to the legacy placeholder GetSchema method.
Of course, the best solution would be if Microsoft would allow us to apply the XmlArrayItemAttribute to collection/list classes and use that in the XmlSerializer. By default it uses the XML type element name in collections, which I feel is a bug because it should be the XML root name when specified or class name when not.
When I get time I'll come back and add an example. For now take a look at the MSDN documentation examples of IXmlSerializable and XmlSchemaProviderAttribute.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlschemaproviderattribute(v=vs.110).aspx
如果您无权访问 Human 类的源(在这种情况下,无法设置 XmlRoot),则可以创建 XmlElementAttribute,然后将其添加到 XmlAttributeOverride 并在创建 XmlSerializer 实例时使用它。 请参阅这篇 MSDN 文章了解更多详细信息。
If you don't have access to the source for the Human class (in which case, setting XmlRoot is not possible), you can create an XmlElementAttribute, then add it to an XmlAttributeOverride and use that when creating an instance of your XmlSerializer. See this MSDN article for more details.
我知道这是一个老问题,但我遇到了同样的问题,并且没有一个解决方案似乎可以解决OP的问题。所以这是我的解决方案(如果您想知道,评论是法语):
这里有一个单元测试类来演示使用和结果:
I know it's an old question but I ran into the same problem and none of the solutions seems to adresse the OP's question. So here is my solution (comments are in french if you wonder) :
And here a unit test class to demonstrate use and results :
我知道它已经过时了,但对于其他人来说 -
在
class Human
之前,添加[XmlType("Person")]
而不是[XmlRoot("Person") ]
I know it's old but for others that will come -
Before
class Human
, add[XmlType("Person")]
instead of[XmlRoot("Person")]