4

Given this generic serialization code:

public virtual string Serialize(System.Text.Encoding encoding)
{
 System.IO.StreamReader streamReader = null;
 System.IO.MemoryStream memoryStream = null;

 memoryStream = new System.IO.MemoryStream();
 System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
 xmlWriterSettings.Encoding = encoding;
 System.Xml.XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings);
 Serializer.Serialize(xmlWriter, this);
 memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
 streamReader = new System.IO.StreamReader(memoryStream);
 return streamReader.ReadToEnd();
}

and this object (gen'd from xsd2code):

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.225")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "Com.Foo.Request")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "Com.Foo.Request", IsNullable = false)]
public partial class REQUEST_GROUP
{

 [EditorBrowsable(EditorBrowsableState.Never)]
 private List<REQUESTING_PARTY> rEQUESTING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private RECEIVING_PARTY rECEIVING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private SUBMITTING_PARTY sUBMITTING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private REQUEST rEQUESTField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private string iDField;

 public REQUEST_GROUP()
 {
  this.rEQUESTField = new REQUEST();
  this.sUBMITTING_PARTYField = new SUBMITTING_PARTY();
  this.rECEIVING_PARTYField = new RECEIVING_PARTY();
  this.rEQUESTING_PARTYField = new List<REQUESTING_PARTY>();
  this.IDField = "2.1";
 }
}

Output from the Serialize with an encode of utf-8:

<?xml version="1.0" encoding="utf-8"?> <REQUEST_GROUP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="2.1" xmlns="Com.Foo.Request"> <RECEIVING_PARTY /> <SUBMITTING_PARTY /> <REQUEST LoginAccountIdentifier="xxx" LoginAccountPassword="yyy" _RecordIdentifier="" _JobIdentifier=""> <REQUESTDATA> <PROPERTY_INFORMATION_REQUEST _SpecialInstructionsDescription="" _ActionType="Submit"> <_DATA_PRODUCT _ShortSubjectReport="Y" /> <_PROPERTY_CRITERIA _City="Sunshine City" _StreetAddress2="" _StreetAddress="123 Main Street" _State="CA" _PostalCode="12345"> <PARSED_STREET_ADDRESS /> </_PROPERTY_CRITERIA> <_SEARCH_CRITERIA /> <_RESPONSE_CRITERIA /> </PROPERTY_INFORMATION_REQUEST> </REQUESTDATA> </REQUEST> </REQUEST_GROUP>

EDIT Question 1: How do I decorate the class in such a fashion, or manipulate the serializer to get rid of all the namespaces in the REQUEST_GROUP node during processing, NOT post-processing with xslt or regex.

Question 2: Bonus point if you could add the doc type too.

Thank you.

Stephen Patten
  • 6,333
  • 10
  • 50
  • 84

2 Answers2

7

You can remove the namespaces like this:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
ns.Add(string.Empty, "Com.Foo.Request");
Serializer.Serialize(xmlWriter, this, ns);

As for adding the doctype, I know it's possible to make a custom XmlWriter and just override WriteStartDocument with a method that makes a call to WriteDocType, but I kind of hope someone else knows an easier way than that.

EDIT: Incidentally, I strongly recommend using using:

using(System.Xml.XmlWriter xmlWriter = XmlWriter.Create(etc.))
{
  // use it here.
}

It automatically handles tidying up of the streams by calling the Dispose method when the block ends.

Flynn1179
  • 11,925
  • 6
  • 38
  • 74
  • @Flynn1179 - most namespaces were removed BUT there is still the xmlns:q1="Com.Foo.Request" in the REQUEST_GROUP, and as a by product all nodes are prefaced by – Stephen Patten May 17 '11 at 23:06
  • I don't see any reference to a `q1` namespace in the question.. where's that coming from? – Flynn1179 May 18 '11 at 06:17
  • 1
    @SPATEN to fix that, also add `ns.Add("", "Com.Foo.Request");` - then the namespace is without an alias. – Marc Gravell May 19 '11 at 08:20
  • @Flynn1179 - XmlSerializer invents it as an alias to use for "Com.Foo.Request"; by default it aliases everything it needs, in case it needs them multiple times – Marc Gravell May 19 '11 at 08:21
  • Ah yeah, forgot about that one. Sorry. I'll update the answer. – Flynn1179 May 19 '11 at 09:07
  • Well, close, but it still has a namespace in the root node. `` FYI I've also done post processing on the file via XDocument doc.Descendants().Attributes().Where(a => a.IsNamespaceDeclaration).Remove(); and it returns the same thing, a node with one namespace in it. So both methods are at least behaving the same – Stephen Patten May 19 '11 at 21:03
  • @SPATEN the namespace is absolutely required, otherwise it is ***not the same xml***; all you can do is choose whether (or not) to use an xmlns alias (and what that should be). If you really don't want the namespace ***at all***, remove the `Namespace=` from the XmlRootAttribute and XmlTypeAttribute. – Marc Gravell May 19 '11 at 22:06
  • @SPATEN - yes, that is forcing it to use the namespace, otherwise it *isn't a match* and will error. The namespace is a fundamental part of the name in xml, and must match exactly (although this can be direct, or indirect via an alias; an alias tends to save space if the namespace is repeated at various points in the file) – Marc Gravell May 19 '11 at 22:33
4

If you just want to remove the namespace aliases, then as already shown you can use XmlSerializerNamespaces to force XmlSerializer to use the namespace explicitly (i.e. xmlns="blah") on each element, rather than declaring an alias and using the alias instead.

However, regardless of what you do with the aliases, the fundamental name of that element is REQUEST_GROUP in the Com.Foo.Request namespace. You can't remove the namespace completely without that representing a breaking change to the underlying data - i.e. somebody somewhere is going to get an exception (due to getting data it didn't expect - specifically REQUEST_GROUP in the root namespace). In C# terms, it is the difference between System.String and My.Custom.String - sure, they are both called String, but that is just their local name.

If you want to remove all traces of the namespace, then a pragmatic option would be to edit away the Namespace=... entries from [XmlRoot(...)] and [XmlType(...)] (plus anywhere else that isn't shown in the example).

If the types are outside of your control, you can also do this at runtime using XmlAttributeOverrides - but a caveat: if you create an XmlSerializer using XmlAttributeOverrides you must cache and re-use it - otherwise your AppDomain will leak (it creates assemblies on the fly per serializer in this mode, and assemblies cannot be unloaded).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900