May 21, 2010

LinqToXML removing empty xmlns attributes

Suppose you need to generate the following XML:
<GenevaLoader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.advent.com/SchemaRevLevel401/Geneva masterschema.xsd" xmlns="http://www.advent.com/SchemaRevLevel401/Geneva">
<PriceRecords>
<PriceRecord>
</PriceRecord>
</PriceRecords>
</GenevaLoader>

Normally you would write the following C# code to accomplish this:

const string ns = "http://www.advent.com/SchemaRevLevel401/Geneva";
XNamespace xnsp = ns;
XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");

XElement root = new XElement( xnsp + "GenevaLoader",
new XAttribute(XNamespace.Xmlns + "xsi", xsi.NamespaceName),
new XAttribute( xsi + "schemaLocation", "http://www.advent.com/SchemaRevLevel401/Geneva masterschema.xsd"));

XElement priceRecords = new XElement("PriceRecords");
root.Add(priceRecords);

for(int i = 0; i < 3; i++)
{
XElement price = new XElement("PriceRecord");
priceRecords.Add(price);
}

doc.Save("geneva.xml");

The problem with this approach is that it adds a additional empty xmlns arrtribute on the “PriceRecords” element, like so :

<GenevaLoader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.advent.com/SchemaRevLevel401/Geneva masterschema.xsd" xmlns="http://www.advent.com/SchemaRevLevel401/Geneva">
<PriceRecords xmlns="">
<PriceRecord>
</PriceRecord>
</PriceRecords>
</GenevaLoader>

The solution is to add the xmlns NameSpace in code to each child and grandchild elements of the root element like so :

XElement priceRecords = new XElement( xnsp + "PriceRecords");
root.Add(priceRecords);

for(int i = 0; i < 3; i++)
{
XElement price = new XElement(xnsp + "PriceRecord");
priceRecords.Add(price);
}

kick it on DotNetKicks.com