How to add namespace prefix for IXmlSerializable type

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

I have a following class definition

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


        
相关标签:
3条回答
  • 2021-01-17 11:44

    Try the following.

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("xmlns", "my", null, "MyNamespace");
        writer.WriteElementString("firstName", FirstName);
        writer.WriteElementString("lastName", LastName);
    }
    
    0 讨论(0)
  • 2021-01-17 11:55

    Do you need to use XmlSerializer? If not, try following code:

    Person.cs

    Add new method:

    public void Serialize(XmlWriter writer)
    {
        writer.WriteStartDocument();
        writer.WriteStartElement("My", "Person", "MyNamespace");
        writer.WriteElementString("My", "FirstName", "MyNamespace", FirstName);
        writer.WriteElementString("My", "LastName", "MyNamespace", LastName);
        writer.WriteEndElement();
        writer.WriteEndDocument();
    }
    

    Usage

    var person = new Person { FirstName = "John", LastName = "Doe" };
    person.Serialize(new XmlTextWriter(Console.Out));
    
    0 讨论(0)
  • 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

    <My:person xmlns:My="MyNamespace">
        <My:firstName>John</My:firstName>
        <My:lastName>Doe</My:lastName>
    </My:person>
    

    It's up to you to consider whether this all is acceptable.
    In the end, <My:person xmlns:My="MyNamespace"> equals <person xmlns="MyNamespace">.

    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;
        }
    
        /// <exception cref="NotSupportedException"/>
        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<XmlRootAttribute>();        
        }
    
    
        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();       
        }
    }
    
    0 讨论(0)
提交回复
热议问题