How to add namespace prefix for IXmlSerializable type

后端 未结 3 2033
执念已碎
执念已碎 2021-01-17 11:29

I have a following class definition

[XmlRoot(ElementName = \"person\",Namespace = \"MyNamespace\")]
public class Perso         


        
3条回答
  •  日久生厌
    2021-01-17 12:03

    The XmlSerializer type doesn't offer anything out-of-the-box to handle this.
    If you really need to use XmlSerializer, you are going to end up with a custom XmlSerializer implementation, which isn't quite open to extend. For this reason the implementation below is more a proof of concept, just to give you an idea or a starting point.
    For brevity I have omitted any error handling and only focussed on the Person class in your question. There's still some work to do to handle any nested complex properties.

    As the Serialize methods are not virtual we'll have to shadow them. The main idea is to direct all overloads to a single one having the custom implementation.

    Because of the customization, we'll have to be more explicit in the Person class when writing the xml elements for its properties by specifying the xml namespace to be applied.

    The code below

    PrefixedXmlSerializer xmlSerializer = new PrefixedXmlSerializer(typeof(Person));
    Person person = new Person { 
        FirstName = "John", 
        LastName = "Doe" 
        };
    xmlSerializer.Serialize(Console.Out, person, person.Namespaces);
    

    results in

    
        John
        Doe
    
    

    It's up to you to consider whether this all is acceptable.
    In the end, equals .

    Person

    [XmlRoot(ElementName = "person", Namespace = NAMESPACE)]
    public class Person : IXmlSerializable
    {
        private const string NAMESPACE = "MyNamespace";
    
        public string FirstName { get; set; }
    
        [XmlNamespaceDeclarations]
        public XmlSerializerNamespaces Namespaces
        {
            get
            {
                var xmlSerializerNamespaces = new XmlSerializerNamespaces();
                xmlSerializerNamespaces.Add("My", NAMESPACE);                
                return xmlSerializerNamespaces;
            }
        }
    
        public string LastName { get; set; }
    
        public XmlSchema GetSchema()
        {
            return null;
        }
    
        /// 
        public void ReadXml(XmlReader reader)
        {
            throw new NotSupportedException();
        }   
    
        public void WriteXml(XmlWriter writer)
        {
            // Specify the xml namespace.
            writer.WriteElementString("firstName", NAMESPACE, FirstName);
            writer.WriteElementString("lastName", NAMESPACE, LastName);
        }
    }
    

    PrefixedXmlSerializer

    public class PrefixedXmlSerializer : XmlSerializer
    {
        XmlRootAttribute _xmlRootAttribute;
    
    
        public PrefixedXmlSerializer(Type type) : base(type)
        {
            this._xmlRootAttribute = type.GetCustomAttribute();        
        }
    
    
        public new void Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
        {
            // Out-of-the-box implementation.
            XmlTextWriter xmlTextWriter = new XmlTextWriter(textWriter);
            xmlTextWriter.Formatting = Formatting.Indented;
            xmlTextWriter.Indentation = 2;
    
            // Call the shadowed version. 
            this.Serialize(xmlTextWriter, o, namespaces, null, null);
        }
    
    
        public new void Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
        {
            // Lookup the xml namespace and prefix to apply.
            XmlQualifiedName[] xmlNamespaces = namespaces.ToArray();                                
            XmlQualifiedName xmlRootNamespace =
                xmlNamespaces
                    .Where(ns => ns.Namespace == this._xmlRootAttribute.Namespace)
                    .FirstOrDefault();
    
            // Write the prefixed root element with its xml namespace declaration.
            xmlWriter.WriteStartElement(xmlRootNamespace.Name, this._xmlRootAttribute.ElementName, xmlRootNamespace.Namespace);            
    
            // Write the xml namespaces; duplicates will be taken care of automatically.
            foreach (XmlQualifiedName xmlNamespace in xmlNamespaces)
            {
                xmlWriter.WriteAttributeString("xmlns", xmlNamespace.Name , null, xmlNamespace.Namespace);
            }
    
            // Write the actual object xml.
            ((IXmlSerializable)o).WriteXml(xmlWriter);
    
            xmlWriter.WriteEndElement();       
        }
    }
    

提交回复
热议问题