Namespace Prefixes with IXmlSerializable
Bit confused on the proper decorators to use, or whatever design might be necessary. When serializing a class which is implementing IXmlSerializable is there a way to include the namespace and its prefix in the XmlRoot element?
Class definition for example.
using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
[XmlRoot("Classy", Namespace = XML_NS)]
public class TestClass : IXmlSerializable
{
private const string XML_PREFIX = ""; // default namespace
private const string XML_NS = "www.123.com";
private const string XML_MEMBER_PREFIX = "me";
private const string XML_MEMBER_NS = "member.com";
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlsn {
get {
XmlSerializerNamespaces xsn = new XmlSerializerNamespaces();
xsn.Add(XML_PREFIX, XML_NS);
xsn.Add(XML_MEMBER_PREFIX, XML_MEMBER_NS);
return xsn;
}
}
void IXmlSerializable.WriteXml(XmlWriter writer) {
writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
XML_MEMBER_NS, Member1);
writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
XML_MEMBER_NS, Member2.ToString());
writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
}
//[XmlElement(ElementName = "Member1.5", Namespace = XML_MEMBER_NS)]
public string Member1 {
get { return "init"; }
set { ; }
}
//[XmlElement(ElementName = "Member2.5", Namespace = XML_MEMBER_NS)]
public int Member2 {
get { return 3; }
set { ; }
}
//[XmlElement(ElementName = "Member3.5", Namespace = XML_NS)]
public string Member3 {
get { return "default namespace"; }
set { ; }
}
// ignore ReadXml/GetSchema
XmlSchema IXmlSerializable.GetSchema() { return null; }
void IXmlSerializable.ReadXml(XmlReader reader) { return; }
}
When serialized via:
TestClass tc = new TestClass();
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
ser(writer, tc, tc.xmlsn); // just a plain XmlWriter to Console.Out
the output is
<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns="www.123.com">
<me:Member1.5 xmlns:me="member.com">init</me:Member1.5>
<me:Member2.5 xmlns:me="member.com">3</me:Member2.5>
<Member3.5>default namespace</Member3.5>
</Classy>
The output I was expecting was:
<?xml version="1.0" encoding="utf-8"?>
<Classy xmlns:me="member.com" xmlns="www.123.com">
<me:Member1.5>init</me:Member1.5>
<me:Member2.5>3</me:Member2.5>
<Member3.5>default namespace</Member3.5>
</Classy>
The second is the output of XmlSerializer if the class's implementation of IXmlSerializable is removed and you uncomment the XmlElement decorators. I know both of the Xml documents returned are valid, but开发者_开发问答 it would be nice to try and remove the redundant namespace declarations. I would assume such a thing is possible, since IXmlSerializable is meant to give greater control over how your class is serialized/deserialized.
Update: A very interesting answer suggested modifying the XmlWriterSettings! It looked like this would clear everything up by modifying the NamespaceHandling property. However this still results in the namespaces being rewritten for each member. Full serialization code below:
XmlSerializer ser = new XmlSerializer(typeof(TestClass));
TestClass tc = new TestClass();
XmlWriterSettings xmlSet = new XmlWriterSettings();
xmlSet.Encoding = System.Text.Encoding.UTF8;
xmlSet.Indent = true;
xmlSet.NamespaceHandling = NamespaceHandling.OmitDuplicates;
XmlWriter writer = XmlWriter.Create(Console.Out, xmlSet);
ser.Serialize(writer, tc); // with/without tc.xmlsn same result
writer.Flush();
writer.Close();
I simply added an String Attribute to WriteXml. It worked!
void IXmlSerializable.WriteXml(XmlWriter writer) {
writer.WriteAttributeString("xmlns:me", "member.com");
writer.WriteAttributeString("xmlns", "www.123.com");
writer.WriteElementString(XML_MEMBER_PREFIX, "Member1.5",
XML_MEMBER_NS, Member1);
writer.WriteElementString(XML_MEMBER_PREFIX, "Member2.5",
XML_MEMBER_NS, Member2.ToString());
writer.WriteElementString(XML_PREFIX, "Member3.5", XML_NS, Member3);
}
and remove [XmlRoot("Classy", Namespace = XML_NS)]
and the xmlsn
property from the class.
Using the WriteAttributeString as suggested is not completely correct. Here is an example on how to use it correctly:
In the WriteXml method at the beginning add something like this:
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
You need to set XmlWriterSetting for it to work. see below pls
http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.aspx
精彩评论