Xml Serialization and Namespace Prefixes

How to generate tag prefixes using XmlSerializer

First off, the atom namespace is normally this:

xmlns:atom="http://www.w3.org/2005/Atom"

In order to get your tags to use the atom namespace prefix, you need to mark your properties with it:

[XmlElement("link", Namespace="http://www.w3.org/2005/Atom")]
public AtomLink AtomLink { get; set; }

You also need tell the XmlSerializer to use it (thanks to @Marc Gravell):

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("atom", "http://www.w3.org/2005/Atom");
XmlSerializer xser = new XmlSerializer(typeof(MyType));
xser.Serialize(Console.Out, new MyType(), ns);

XML Serialization and namespace prefixes

To control the namespace alias, use XmlSerializerNamespaces.

[XmlRoot("Node", Namespace="http://flibble")]
public class MyType {
[XmlElement("childNode")]
public string Value { get; set; }
}

static class Program
{
static void Main()
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("myNamespace", "http://flibble");
XmlSerializer xser = new XmlSerializer(typeof(MyType));
xser.Serialize(Console.Out, new MyType(), ns);
}
}

If you need to change the namespace at runtime, you can additionally use XmlAttributeOverrides.

How to add namespace prefix for IXmlSerializable type

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();
}
}

C# XmlSerializer define namespace with prefix in a child node

This is possible. The code below does what you are asking for.

class Program
{
static void Main(string[] args)
{
SerializeObject("XmlNamespaces.xml");
}

public static void SerializeObject(string filename)
{
var mySerializer = new XmlSerializer(typeof(Container));
// Writing a file requires a TextWriter.
TextWriter myWriter = new StreamWriter(filename);

// Creates an XmlSerializerNamespaces and adds two
// prefix-namespace pairs.
var myNamespaces = new XmlSerializerNamespaces();
//myNamespaces.Add("a", "http://www.UKMail.com/Services/Contracts/DataContracts");

Container container = new Container
{
Info = new CancelConsignmentRequest
{
request = new CancelConsignmentRequestInfo
{
AuthenticationToken = "token",
ConsignmentNumber = "12345",
Username = "username"
}
}
};

mySerializer.Serialize(myWriter, container, myNamespaces);
myWriter.Close();
}
}

public class Container
{
public CancelConsignmentRequest Info { get; set; } = new CancelConsignmentRequest();
}

public class CancelConsignmentRequest
{
public CancelConsignmentRequestInfo request { get; set; } = new CancelConsignmentRequestInfo();
}

[XmlRoot(Namespace = "http://www.UKMail.com/Services/Contracts/ServiceContracts")]
public class CancelConsignmentRequestInfo
{
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces(
new[] { new XmlQualifiedName("a", "http://www.UKMail.com/Services/Contracts/DataContracts"), });
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 0)]
public string AuthenticationToken { get; set; }
[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 1)]
public string Username { get; set; }

[XmlElement(Namespace = "http://www.UKMail.com/Services/Contracts/DataContracts", Order = 2)]
public string ConsignmentNumber { get; set; }
}

XML Serializing Element with prefix

Fields, properties, and objects can have a namespace associated with them for serialization purposes. You specify the namespaces using attributes such as [XmlRoot(...)], [XmlElement(...)], and [XmlAttribute(...)]:

[XmlRoot(ElementName = "MyRoot", Namespace = MyElement.ElementNamespace)]
public class MyElement
{
public const string ElementNamespace = "http://www.mynamespace.com";
public const string SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance";

[XmlAttribute("schemaLocation", Namespace = SchemaInstanceNamespace)]
public string SchemaLocation = "http://www.mynamespace.com/schema.xsd";

public string Content { get; set; }
}

Then you associate the desired namespace prefixes during serialization by using the XmlSerializerNamespaces object:

var obj = new MyElement() { Content = "testing" };
var namespaces = new XmlSerializerNamespaces();
namespaces.Add("xsi", MyElement.SchemaInstanceNamespace);
namespaces.Add("myns", MyElement.ElementNamespace);
var serializer = new XmlSerializer(typeof(MyElement));
using (var writer = File.CreateText("serialized.xml"))
{
serializer.Serialize(writer, obj, namespaces);
}

The final output file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<myns:MyRoot xmlns:myns="http://www.mynamespace.com" xsi:schemaLocation="http://www.mynamespace.com/schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<myns:Content>testing</myns:Content>
</myns:MyRoot>

Serializing class adds prefixes automatically to XML elements

The XMLSerializer supports providing a default namespace e.g.

string defaultNamespace = "http://tempuri.org/Logon";

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, defaultNamespace);

XmlSerializer xs = new XmlSerializer(typeof(T), defaultNamespace);

C# XML Deserialization with multiple namespaces and namespace prefixes

Try to change your XmlAttribute for property Siri from [XmlAttribute("siri")] to [XmlAttribute(Namespace = "http://www.siri.org.uk/siri")]

[XmlRoot(nameof(Trias), Namespace = "http://www.vdv.de/trias")]
public class Trias
{

[XmlAttribute("version")]
public string Version { get; set; }

[XmlAttribute("xmlns")]
public string Xmlns { get; set; }

[XmlAttribute(Namespace = "http://www.siri.org.uk/siri")]
public string Siri { get; set; }
}


Related Topics



Leave a reply



Submit