How to set the default XML namespace for an XDocument

How can I set the default namespace of an existing XDocument (so I can deserialize it with DataContractSerializer). I tried the following:

var doc = XDocument.Parse("<widget/>");
var attrib = new XAttribute("xmlns",
                            "http://schemas.datacontract.org/2004/07/Widgets");
doc.Root.Add(attrib);

The exception I get is is The prefix '' cannot be redefined from '' to 'http://schemas.datacontract.org/2004/07/Widgets' within the same start element tag.

Any ideas?


Not sure if this already worked in .net 3.5 or only in 4, but this works fine for me:

XNamespace ns = @"http://mynamespace";
var result = new XDocument(
    new XElement(ns + "rootNode",
        new XElement(ns + "child",
            new XText("Hello World!")
         )
     )
 );

produces this document:

<rootNode xmlns="http://mynamespace">
    <child>Hello World!</child>
</rootNode>

Important is to always use the ns + "NodeName" syntax.


It seems that Linq to XML does not provide an API for this use case (disclaimer: I didn't investigate very deep). If change the namespace of the root element, like this:

XNamespace xmlns = "http://schemas.datacontract.org/2004/07/Widgets";
doc.Root.Name = xmlns + doc.Root.Name.LocalName;

Only the root element will have its namespace changed. All children will have an explicit empty xmlns tag.

A solution could be something like this:

public static void SetDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
    if(xelem.Name.NamespaceName == string.Empty)
        xelem.Name = xmlns + xelem.Name.LocalName;
    foreach(var e in xelem.Elements())
        e.SetDefaultXmlNamespace(xmlns);
}

// ...
doc.Root.SetDefaultXmlNamespace("http://schemas.datacontract.org/2004/07/Widgets");

Or, if you prefer a version that does not mutate the existing document:

public XElement WithDefaultXmlNamespace(this XElement xelem, XNamespace xmlns)
{
    XName name;
    if(xelem.Name.NamespaceName == string.Empty)
        name = xmlns + xelem.Name.LocalName;
    else
        name = xelem.Name;
    return new XElement(name,
                    from e in xelem.Elements()
                    select e.WithDefaultXmlNamespace(xmlns));
}