更改自动生成的类的XmlSerialization的名称空间处理

时间:2018-06-27 09:11:06

标签: c# .net xml xsd xml-serialization

我目前正在创建一堆文件,然后应由其他程序使用。它们大多数是XML文件。自然,我从程序中提取了.xsd文件,并使用xsd.exe工具自动生成了C#类,效果很好。

问题

序列化自动生成的类会生成一个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>

到目前为止,我尚未发现xsixsd都没有用到,但这并不是真正的问题。

程序期望的XML看起来像这样:

<n1:root xmlns:n1="ns1">
    <group>
        <item>foo</item>
        <item>bar</item>
    </group>
</n1:root

反序列化时,两个xml都应该导致相同的结果,因此我不会将错误放在xsd.exe上。

但是,当尝试在程序中打开生成的xml时,会产生“对象引用未设置为对象实例”错误。 xmlns:xsixmlns:xsd都必须删除,并且必须使用xmlns:n1而不是默认名称空间。

我尝试过的

起初我以为我可以使用IXmlSerializable手动序列化该类,但是由于xsd.exe自动添加XmlTypeAttributeXmlRootAttribute,因此在序列化时会产生运行时错误。 / p>

产生的错误显示为InvalidOperationException: Only XmlRoot attribute may be specified for the type myNs.MyClass. Please use XmlSchemaProviderAttribute to specify schema type.

我不认为使用XmlSchemaProviderAttribute是一个好主意,因为它破坏了根据给定模式自动生成类的想法。 (该模式可能会在程序的将来版本中更改)


如果您想要一个最小的示例,下面的代码可以在rextester.com上运行:(请注意,当我使用.NET Framework 4.7时,rextester使用.NET Framework 4.5,因此,使用新功能的所有答案都更多。比欢迎)

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

1 个答案:

答案 0 :(得分:1)

我可能完全遗漏了这一点,因为我不知道您“从程序中提取.xsd文件”是什么意思,也不知道您正在编写哪种集成。

如果您的最终目标只是简单地调整命名空间,以便程序可以吃掉您的数据,请放弃所有自动生成的XmlSerialier属性,并告诉类和序列化程序您的外观。有时,涉及序列化程序的事情少得多,如果您愿意,它将独自完成很多工作。

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>

这看起来与您的示例不完全相同,但是通过对类进行一些调整,您可以组合Item和Value标记。