序列化xml文件的一部分。想要根目录上的命名空间,而不是序列化的子元素

时间:2015-02-17 21:25:58

标签: c# namespaces xmlserializer

我试图创建一个类似于:

的Xml文件
<RootLevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.MyCompany.com/MySchema.xsd">
    <Level1>
        <Level2>
        </Level2>
    </Level1 >
    <Level1>
        <Level2>
        </Level2>
    </Level1 >
    etc. repeats hundreds of times
</RootLevel>

我使用xsd.exe实用程序从我的xml架构定义文件生成了一些类。他们看起来像:

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://MyCompany.com/MySchema.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.MyCompany.com/MySchema.xsd", IsNullable = false)]
public partial class RootLevel
{
    private List<Level1> level1Field;

    public List<Level1> Level1Field 
    {
        get { return this.level1Field;}
        set {this.level1Field = value;}
    }
}

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.MyCompany.com/MySchema.xsd")]
public partial class Level1
{
    private List<Level2> level2Field;

    public List<Level2> Level2Field 
    {
        get { return this.level2Field;}
        set {this.level2Field = value;}
    }

    /* other properties on Level1 go here*/
}

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.MyCompany.com/MySchema.xsd")]
public partial class Level2
{
    /* properties on Level2 go here*/
}    

我通过使用XmlWriter.WriteStartElement()写出RootLevel元素来创建这个文件,然后通过创建Level1对象并使用XmlSerializer将它们序列化来写出文件的其余部分。

目标

我希望文件只在RootLevel元素上有名称空间。

如果您有兴趣,这是我到目前为止尝试的内容:

起点

一开始,我的RootLevel元素没有任何名称空间。 我的Level1和Level2元素有名称空间。

第1步:

我尝试通过覆盖类别Level1和Level2的XmlTypeAttributes上的命名空间来从Level1和Level2元素中删除命名空间。

XmlTypeAttribute attribute = new XmlTypeAttribute();
attribute.Namespace = string.Empty;

XmlAttributes attributes = new XmlAttributes();
attributes.XmlType = attribute;

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Level1), attributes);
overrides.Add(typeof(Level2), attributes);

this.xmlSerializer = new XmlSerializer(typeof(Level1), overrides);

第1步结果

命名空间已从Level2中删除,但未从Level1中删除。

第2步

添加了一些代码以尝试从Level1中删除命名空间。我尝试使用XmlSerializer.Serialize()方法的namespaces参数来使用空名称空间。注意&#34; level1&#34;是&#34; Level1&#34;。

的对象
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("", "");

this.xmlSerializer.Serialize(this.xmlFileWriter, level1, namespaces);

第2步结果

从Level1和Level2中删除命名空间。到现在为止还挺好!现在我需要做的就是将命名空间内容添加到RootLevel。

第3步

由于RootLevel未被序列化,我添加了一些XmlWriter代码以尝试将名称空间添加到RootLevel。

string defaultNamespace = "http://www.MyCompany.com/MySchema.xsd";
this.xmlFileWriter.WriteStartElement("RootLevel", defaultNamespace);
this.xmlFileWriter.WriteAttributeString("xmlns", "xsi", "", "http://www.w3.org/2001/XMLSchema-instance");
this.xmlFileWriter.WriteAttributeString("xmlns", "xsd", "", "http://www.w3.org/2001/XMLSchema");

第3步结果

名称空间已添加到RootLevel中。好极了!。 但是,现在每个Level1元素都有一个 xmlns =&#34;&#34; 属性。哎呀!

<RootLevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.MyCompany.com/MySchema.xsd">
    <Level1 xmlns="">
        <Level2>
        </Level2>
    </Level1 >
    <Level1 xmlns="">
        <Level2>
        </Level2>
    </Level1 >
    etc. repeats hundreds of times
</RootLevel>

那为什么会这样呢?

1 个答案:

答案 0 :(得分:0)

您没有发布原始代码,因此我不确切地知道您出错的地方,但我能够获得您想要的XML,如下所示:

  1. 提取静态助手类XmlNamespaces以保存命名空间字符串并将其声明为const个字符串。在您的问题中,您有时使用"http://MyCompany.com/MySchema.xsd"但有时使用"http://www.MyCompany.com/MySchema.xsd"。这可能只是问题中的拼写错误,但如果您的代码使用不一致,则会导致错误。

  2. XmlRootAttribute

    之外,将Level1应用于课程XmlTypeAttribute
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = XmlNamespaces.Default)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = XmlNamespaces.Default, IsNullable = false)]
    public partial class Level1
    {
        // Properties 
    }
    
  3. 编写根元素时,将默认命名空间字符串传递给XmlWriter.WriteStartElement(string, string)

  4. 总体代码如下:

    public static class XmlNamespaces
    {
        public const string Default = "http://MyCompany.com/MySchema.xsd";
        public const string xsi = "http://www.w3.org/2001/XMLSchema-instance";
        public const string xsd = "http://www.w3.org/2001/XMLSchema";
    
        public static XmlSerializerNamespaces XmlSerializerNamespaces
        {
            get
            {
                var namespaces = new XmlSerializerNamespaces();
                namespaces.Add("", XmlNamespaces.Default);
                namespaces.Add("xsi", XmlNamespaces.xsi);
                namespaces.Add("xsd", XmlNamespaces.xsd);
                return namespaces;
            }
        }
    }
    
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = XmlNamespaces.Default)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = XmlNamespaces.Default, IsNullable = false)] // Added this and used const string from XmlNamespaces class
    public partial class Level1
    {
        private List<Level2> level2Field;
    
        public List<Level2> Level2Field
        {
            get { return this.level2Field; }
            set { this.level2Field = value; }
        }
    
        /* other properties on Level1 go here*/
    }
    
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = XmlNamespaces.Default)] // Used const string  from XmlNamespaces class
    public partial class Level2
    {
        /* properties on Level2 go here*/
    }
    
    public static class XmlSerializationUtilities
    {
        public static void WriteList<TItem>(string rootName, XmlSerializerNamespaces namespaces, IEnumerable<TItem> list, TextWriter textWriter)
        {
            var namespaceList = namespaces.ToArray();
            string defaultNamespace = null;
            foreach (var ns in namespaceList)
            {
                if (string.IsNullOrEmpty(ns.Name))
                {
                    defaultNamespace = ns.Namespace;
                    break;
                }
            }
    
            var settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "    ";
    
            using (var writer = XmlWriter.Create(textWriter, settings))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement(rootName, defaultNamespace);
    
                foreach (var ns in namespaceList)
                    if (!string.IsNullOrEmpty(ns.Name))
                        writer.WriteAttributeString("xmlns", ns.Name, null, ns.Namespace);
    
                var serializer = new XmlSerializer(typeof(TItem));
                foreach (var item in list)
                {
                    serializer.Serialize(writer, item);
                }
    
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }
    }
    
    public static class TestClass
    {
        public static void Test()
        {
            var list = new List<Level1> { new Level1 { Level2Field = new List<Level2> { new Level2(), new Level2() } }, new Level1 { Level2Field = new List<Level2> { new Level2(), new Level2(), new Level2(), new Level2() } } };
    
            string xml;
    
            using (var writer = new StringWriter())
            {
                XmlSerializationUtilities.WriteList("RootLevel", XmlNamespaces.XmlSerializerNamespaces, list, writer);
                xml = writer.ToString();
    
                Debug.WriteLine(xml);
            }
        }
    }
    

    输出

    <?xml version="1.0" encoding="utf-16"?>
    <RootLevel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://MyCompany.com/MySchema.xsd">
        <Level1>
            <Level2Field>
                <Level2 />
                <Level2 />
            </Level2Field>
        </Level1>
        <Level1>
            <Level2Field>
                <Level2 />
                <Level2 />
                <Level2 />
                <Level2 />
            </Level2Field>
        </Level1>
    </RootLevel>