代码之家  ›  专栏  ›  技术社区  ›  SourceOverflow

更改自动生成的类“XmlSerialization”的命名空间处理

  •  0
  • SourceOverflow  · 技术社区  · 8 年前

    我目前正在创建一堆文件,然后应该由另一个程序使用。其中大部分是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>
    

    两者 xsi 和 xsd 到目前为止我发现的东西都没用,但那应该不是问题。

    程序期望的XML如下所示:

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

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

    但是,当试图在程序中打开生成的XML时,它会产生“对象引用未设置为对象实例”错误。两者 xmlns:xsi 和 xmlns:xsd 必须移除,并且必须使用 xmlns:n1 而不是默认的命名空间。

    我试过的

    起初我想,我可以使用 IXmlSerializable ,但是在序列化时会产生运行时错误,因为xsd.exe会自动添加 XmlTypeAttribute 和 XmlRootAttribute 是的。

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

    我不认为使用xmlschemaproviderattribute是一个好主意,因为这违背了从给定模式自动生成类的想法。(在程序的未来版本中,模式可能会改变)


    如果你想要一个最小的例子,这里有一些运行在 rextester.com :(注意,rextester使用.net framework 4.5,而我使用的是.netframework4.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);
            }
        }
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Van Amburg    8 年前

    我可能完全忽略了这一点,因为我不知道您所说的“从程序中提取.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标记组合起来。