Freigeben über


Controlling Namespace Serialization of LINQ to XML

You can explicitly control how LINQ to XML serializes the namespaces for an XML tree.  You can control whether a namespace is serialized as the default namespace for a tree, or whether the namespace will use a prefix.  Namespace declarations look like attribute declarations, so to simplify the LINQ to XML tree, LINQ to XML contains the notion of ‘namespace attributes’.  These are XAttribute objects that are ‘attributes’ of an XElement object, but are there solely to control namespace serialization.  You can determine if an XAttribute object is a real attribute or a namespace attribute by looking at the IsNamespaceDeclaration property of the XAttribute object.  If you have an existing XML tree and you want to control its serialization, you can first remove all ‘namespace attributes’, and then add the namespace attributes that will cause the XML tree to be serialized as you wish.  There are two varieties of namespace attributes:

  • This blog is inactive.
    New blog: EricWhite.com/blog

    Blog TOCA namespace attribute that causes the namespace to be serialized as the default namespace.  This attribute has the special name of “xmlns”, and has the value of the namespace name.

  • A namespace attribute that causes the namespace to be serialized with a specific namespace prefix.  This attribute has the name of XNamespace.Xmlns + "x", where x is the desired prefix.  As with the attribute that causes serialization as the default namespace, its value is the namespace name.

Serializing as the Default Namespace

Consider the following small example:

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'>
<a:Child>1</a:Child>
</a:Root>");

As written, this XML tree will serialize with a namespace prefix of ‘a’, but we can explicitly control this.  The following example first removes all ‘namespace attributes’, and then adds a namespace attribute that specifies that the namespace be serialized as the default namespace.  If you add a namespace attribute with the special name of “xmlns”, then than namespace will be serialized as the default namespace.

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'>
<a:Child>1</a:Child>
</a:Root>");

// Remove all namespace attributes.
root.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove();

// Specify that the namespace will be serialized as the default namespace.
root.Add(new XAttribute("xmlns", "https://www.adventureworks.com"));

Console.WriteLine(root);

This outputs:

<Rootxmlns="https://www.adventureworks.com">
<Child>1</Child>
</Root>

Serializing with a Specific Namespace Prefix

You can also change the namespace prefix for serialization.  If you add a namespace attribute with a name of XNamespace.Xmlns + “b”, then the namespace will serialize with an attribute of ‘b’:

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'>
<a:Child>1</a:Child>
</a:Root>");

// Remove all namespace attributes.
root.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove();

// Specify that the namespace will be serialized with a namespace prefix of 'b'.
root.Add(new XAttribute(XNamespace.Xmlns + "b", "https://www.adventureworks.com"));

Console.WriteLine(root);

This causes the XML to be serialized like this:

<b:Rootxmlns:b="https://www.adventureworks.com">
<b:Child>1</b:Child>
</b:Root>

Controlling Serialization of Multiple Prefixes

If you have elements or attributes in multiple namespaces in an XML tree, you can follow these same two techniques to control how each namespace is serialized.  The following XML tree serializes with the ‘https://www.adventureworks.com’ namespace with a prefix of ‘a’, and the ‘https://www.contoso.com’ namespace with a prefix of ‘c’.

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'
xmlns:c='https://www.contoso.com'>
<c:Child>1</c:Child>
</a:Root>");
Console.WriteLine(root);

If you want to serialize this XML tree with namespace prefixes of ‘x’ and ‘y’, you can do so like this:

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'
xmlns:c='https://www.contoso.com'>
<c:Child>1</c:Child>
</a:Root>");

// Remove all namespace attributes.
root.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove();

// Specify prefixes for both namespaces
root.Add(
new XAttribute(XNamespace.Xmlns + "x", "https://www.adventureworks.com"),
new XAttribute(XNamespace.Xmlns + "y", "https://www.contoso.com"));

Console.WriteLine(root);

This produces the following output:

<x:Rootxmlns:x="https://www.adventureworks.com"
xmlns:y="https://www.contoso.com">
<y:Child>1</y:Child>
</x:Root>

You could also decide to serialize one or the other namespace as the default namespace.

XElement root = XElement.Parse(
@"<a:Root xmlns:a='https://www.adventureworks.com'
xmlns:c='https://www.contoso.com'>
<c:Child>1</c:Child>
</a:Root>");

// Remove all namespace attributes.
root.DescendantsAndSelf().Attributes().Where(n => n.IsNamespaceDeclaration).Remove();

// Specify prefixes for both namespaces
root.Add(
new XAttribute("xmlns", "https://www.adventureworks.com"),
new XAttribute(XNamespace.Xmlns + "y", "https://www.contoso.com"));

Console.WriteLine(root);

This outputs:

<Rootxmlns="https://www.adventureworks.com"
xmlns:y="https://www.contoso.com">
<y:Child>1</y:Child>
</Root>