How to add xsi schemalocation to root c # object XmlSerializer

后端 未结 2 1355
情歌与酒
情歌与酒 2020-12-09 18:34

I am using XmlSerializer to create an object representing an XML file and now i want to add a schemalocation to the rootelement of my xml file. I can add namespaces like the

2条回答
  •  温柔的废话
    2020-12-09 19:01

    Let's assume the following XSD:

    
    
    
        
            
                
                    
                    
                
            
          
    
    

    There are two ways at least to do it. The first one relies on inheritance and how you can play with the serializer annotations.

    xsd.exe generates this:

    //------------------------------------------------------------------------------
    // 
    //     This code was generated by a tool.
    //     Runtime Version:4.0.30319.18034
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // 
    //------------------------------------------------------------------------------
    
    using System.Xml.Serialization;
    
    // 
    // This source code was auto-generated by xsd, Version=4.0.30319.1.
    // 
    
    /// 
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://tempuri.org/XMLSchema.xsd")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/XMLSchema.xsd", IsNullable=false)]
    public partial class elementB {
    
        private string firstNameField;
    
        private string lastNameField;
    
        /// 
        public string FirstName {
            get {
                return this.firstNameField;
            }
            set {
                this.firstNameField = value;
            }
        }
    
        /// 
        public string LastName {
            get {
                return this.lastNameField;
            }
            set {
                this.lastNameField = value;
            }
        }
    }
    

    To "inject" the xsi:schemaLocation add a new class, elementA : elementB; notice:

    • System.Xml.Serialization.XmlRootAttribute setup
    • schemaLocation property setup.

    Test program:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Serialization;
    using System.IO;
    using System.Xml;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                elementB b = new elementB();
                b.FirstName = "P";
                b.LastName = "G";
    
                XmlSerializer ser = new XmlSerializer(typeof(elementB));
                StringBuilder sb = new StringBuilder();
                using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
                {
                    ser.Serialize(writer, b);
                }
                Console.WriteLine(sb.ToString());
    
                elementA a = new elementA();
                a.FirstName = "P";
                a.LastName = "G";
                a.schemaLocation = "http://tempuri.org/XMLSchema.xsd me";
                ser = new XmlSerializer(typeof(elementA));
                sb = new StringBuilder();
                using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true }))
                {
                    ser.Serialize(writer, a);
                }
                Console.WriteLine(sb.ToString());
            }
        }
    }
    
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/XMLSchema.xsd")]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/XMLSchema.xsd", ElementName = "elementB", IsNullable = false)]
    public partial class elementA : elementB
    {
    
        private string torefField;
    
        /// 
        [System.Xml.Serialization.XmlAttributeAttribute(Form = System.Xml.Schema.XmlSchemaForm.Qualified, Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
        public string schemaLocation
        {
            get
            {
                return this.torefField;
            }
            set
            {
                this.torefField = value;
            }
        }
    }
    

    Generates the expected result:

    
    
      P
      G
    
    
    
      Petru
      Gardea
    
    

    The second way relies on a custom writer that will inject what you want, wherever you want it (assuming the appropriate logic).

    You implement a custom XmlWriter:

    class MyXmlWriter : XmlWriter
    {
        XmlWriter _writer;
        bool _docElement = true;
    
        public string SchemaLocation { get; set; }
        public string NoNamespaceSchemaLocation { get; set; }
    
        public MyXmlWriter(XmlWriter writer)
        {
            _writer = writer;
        }
    
        (other methods omitted)
    
        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            _writer.WriteStartElement(prefix, localName, ns);
            if (_docElement)
            {
                if (!string.IsNullOrEmpty(SchemaLocation))
                {
                    _writer.WriteAttributeString("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", SchemaLocation);
                }
                if (!string.IsNullOrEmpty(NoNamespaceSchemaLocation))
                {
                    _writer.WriteAttributeString("xsi", "noNamesapceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance", NoNamespaceSchemaLocation);
                }
                _docElement = false;
            }
        }
    
        (other methods omitted)
    
    }
    

    A modified test program:

    static void Main(string[] args)
    {
        elementB b = new elementB();
        b.FirstName = "P";
        b.LastName = "G";
    
        XmlSerializer ser = new XmlSerializer(typeof(elementB));
        StringBuilder sb = new StringBuilder();
        using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true })) 
        {
            ser.Serialize(writer, b);
        }
        Console.WriteLine(sb.ToString());
    
        sb = new StringBuilder();
    
        using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true }))
        {
            MyXmlWriter newWriter = new MyXmlWriter(writer) { SchemaLocation = "http://tempuri.org/XMLSchema.xsd me" };
            ser.Serialize(newWriter, b);
        }
        Console.WriteLine(sb.ToString());
    }
    

    The result is the same...

    
    
      P
      G
    
    
    
      P
      G
    
    

提交回复
热议问题