更改自动生成的 class' XmlSerialization 的名称空间处理
Change autogenerated class' XmlSerialization's namespace handling
我目前正在创建一堆文件,供其他程序使用。其中大部分是 XML- 文件。当然,我从程序中提取了 .xsd 文件并使用 xsd.exe 工具自动生成 C#-classes,效果相当好。
问题
序列化自动生成的 class 会生成如下 xml 文件:
<root xmlns="ns1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<group xmlns="">
<item>foo</item>
<item>bar</item>
</group>
</root>
xsi
和 xsd
都没有用在我目前发现的任何东西中,但这应该不是问题。
程序期望的 XML 看起来像这样:
<n1:root xmlns:n1="ns1">
<group>
<item>foo</item>
<item>bar</item>
</group>
</n1:root
两个 xml 在反序列化时应该产生相同的结果,所以我没有把错误放在 xsd.exe.
但是,当试图在程序中打开生成的xml时,会产生"Object reference not set to an instance of an object"错误。 xmlns:xsi
和 xmlns:xsd
都必须删除,并且必须使用 xmlns:n1
而不是默认命名空间。
我试过的
起初我想,我可以使用 IXmlSerializable
手动序列化 class,但是在序列化时会产生运行时错误,因为 xsd.exe 会自动添加 XmlTypeAttribute
和 XmlRootAttribute
.
产生的错误读取 InvalidOperationException: Only XmlRoot attribute may be specified for the type myNs.MyClass. Please use XmlSchemaProviderAttribute to specify schema type.
我认为使用 XmlSchemaProviderAttribute 不是一个好主意,因为这违背了从给定模式自动生成 class 的想法。 (架构可能会在程序的未来版本中发生变化)
如果您想要一个最小的示例,这里有一些在 rextester.com 上运行的代码:(请注意,rextester 使用 .NET Framework 4.5,而我使用的是 .NET Framework 4.7,因此任何使用新功能的答案非常欢迎)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Rextester
{
// AUTOGENERATED
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.somens.com", IsNullable=false)]
public partial class Test {
[System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
[System.Xml.Serialization.XmlArrayItemAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public Item[] Group { get; set; }
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
public partial class Item {
[System.Xml.Serialization.XmlAttributeAttribute()]
public int Value { get; set; }
}
// CUSTOM
public partial class Test : IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
foreach (var item in Group) {
writer.WriteStartElement("item");
writer.WriteAttributeString("Value", item.Value.ToString());
writer.WriteEndElement();
}
}
}
public class Program
{
public static void Main(string[] args)
{
var t = new Test();
t.Group = new Item[] { new Item { Value = 5}, new Item { Value = 10} };
var serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(Console.Out, t);
}
}
}
我可能完全忽略了重点,因为我不知道 "extracted the .xsd files from the program" 是什么意思,也不知道您正在编写哪种集成。
如果您的最终目标只是获得正确的命名空间,以便程序吃掉您的数据,请放弃所有自动生成的 XmlSerialier 属性,并告诉 class 和序列化程序您希望如何处理看。有时对于序列化程序来说,少即是多,如果你愿意,它会自己做很多工作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Rextester
{
[XmlRoot("root", Namespace = "ns1")]
public partial class Test
{
[XmlArray(ElementName = "Group", Namespace = "")]
public Item[] Group { get; set; }
}
public partial class Item
{
public int Value { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var t = new Test();
t.Group = new Item[] { new Item { Value = 5 }, new Item { Value = 10 } };
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add("n1", "ns1");
var serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(Console.Out, t,xsn);
}
}
}
哪个输出。
<?xml version="1.0" encoding="IBM437"?>
<n1:root xmlns:n1="ns1">
<Group>
<Item>
<Value>5</Value>
</Item>
<Item>
<Value>10</Value>
</Item>
</Group>
</n1:root>
这看起来与您的示例并不完全相同,但是通过对您的 class 进行一些修改,您可以组合 Item 和 Value 标签。
我目前正在创建一堆文件,供其他程序使用。其中大部分是 XML- 文件。当然,我从程序中提取了 .xsd 文件并使用 xsd.exe 工具自动生成 C#-classes,效果相当好。
问题
序列化自动生成的 class 会生成如下 xml 文件:
<root xmlns="ns1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<group xmlns="">
<item>foo</item>
<item>bar</item>
</group>
</root>
xsi
和 xsd
都没有用在我目前发现的任何东西中,但这应该不是问题。
程序期望的 XML 看起来像这样:
<n1:root xmlns:n1="ns1">
<group>
<item>foo</item>
<item>bar</item>
</group>
</n1:root
两个 xml 在反序列化时应该产生相同的结果,所以我没有把错误放在 xsd.exe.
但是,当试图在程序中打开生成的xml时,会产生"Object reference not set to an instance of an object"错误。 xmlns:xsi
和 xmlns:xsd
都必须删除,并且必须使用 xmlns:n1
而不是默认命名空间。
我试过的
起初我想,我可以使用 IXmlSerializable
手动序列化 class,但是在序列化时会产生运行时错误,因为 xsd.exe 会自动添加 XmlTypeAttribute
和 XmlRootAttribute
.
产生的错误读取 InvalidOperationException: Only XmlRoot attribute may be specified for the type myNs.MyClass. Please use XmlSchemaProviderAttribute to specify schema type.
我认为使用 XmlSchemaProviderAttribute 不是一个好主意,因为这违背了从给定模式自动生成 class 的想法。 (架构可能会在程序的未来版本中发生变化)
如果您想要一个最小的示例,这里有一些在 rextester.com 上运行的代码:(请注意,rextester 使用 .NET Framework 4.5,而我使用的是 .NET Framework 4.7,因此任何使用新功能的答案非常欢迎)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Rextester
{
// AUTOGENERATED
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.somens.com", IsNullable=false)]
public partial class Test {
[System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
[System.Xml.Serialization.XmlArrayItemAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public Item[] Group { get; set; }
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.7.2558.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.somens.com")]
public partial class Item {
[System.Xml.Serialization.XmlAttributeAttribute()]
public int Value { get; set; }
}
// CUSTOM
public partial class Test : IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
throw new NotImplementedException();
}
public void WriteXml(XmlWriter writer)
{
foreach (var item in Group) {
writer.WriteStartElement("item");
writer.WriteAttributeString("Value", item.Value.ToString());
writer.WriteEndElement();
}
}
}
public class Program
{
public static void Main(string[] args)
{
var t = new Test();
t.Group = new Item[] { new Item { Value = 5}, new Item { Value = 10} };
var serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(Console.Out, t);
}
}
}
我可能完全忽略了重点,因为我不知道 "extracted the .xsd files from the program" 是什么意思,也不知道您正在编写哪种集成。
如果您的最终目标只是获得正确的命名空间,以便程序吃掉您的数据,请放弃所有自动生成的 XmlSerialier 属性,并告诉 class 和序列化程序您希望如何处理看。有时对于序列化程序来说,少即是多,如果你愿意,它会自己做很多工作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Rextester
{
[XmlRoot("root", Namespace = "ns1")]
public partial class Test
{
[XmlArray(ElementName = "Group", Namespace = "")]
public Item[] Group { get; set; }
}
public partial class Item
{
public int Value { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var t = new Test();
t.Group = new Item[] { new Item { Value = 5 }, new Item { Value = 10 } };
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add("n1", "ns1");
var serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(Console.Out, t,xsn);
}
}
}
哪个输出。
<?xml version="1.0" encoding="IBM437"?>
<n1:root xmlns:n1="ns1">
<Group>
<Item>
<Value>5</Value>
</Item>
<Item>
<Value>10</Value>
</Item>
</Group>
</n1:root>
这看起来与您的示例并不完全相同,但是通过对您的 class 进行一些修改,您可以组合 Item 和 Value 标签。