views:

522

answers:

4

I have a function which generates xml for a list object:

public XDocument ToXML()
{
    foreach (var row in this)
    {
        var xml = row.ToXml();
        template.Root.Add(xml);
    }
    return template;
}

The template.ToString() reads: <RootElement xmlns="urn:testTools">

The xml reads: <Example><SubElement>testData</SubElement></Example>

After the add function has executed the template.ToString() reads: <RootElement xmlns="urn:testTools"><Example xmlns=""><SubElement>testData</SubElement></Example>

So for some reason there was an empty namespace added, how can i prevent it from doing so?

+2  A: 

Set the namespace on the Example and SubElement elements to the same as the RootElement. It is adding the xmlns="" to clear the namespace for these elements.

Foole
Ok I now understand why it does that, thank you!But it's only useful if you merge different xml, with different namespaces, not while creating a single xml document. Furthermore an empty namespace tag isn't valid xml.
JJoos
@JJoos: an empty namespace is certainly valid XML. What makes you think it isn't? Also, keep in mind a single XML document may have elements and attributes from many namespaces.
John Saunders
@John Saunders you're right, thought it was illegal because of:http://www.w3.org/TR/REC-xml-names/ Section 2.2 first line.Kind of confusing. Thanks.
JJoos
A: 

It could be that your root needs to be closed properly:

 <RootElement xmlns="urn:testTools"> to <RootElement xmlns="urn:testTools"/> 
JayD
A: 

I solved it by replacing the elements with an regex. Foole's solution didn't work, because i didn't always now the exact namespace at that point in code.

So here's my dirty hack that works:

template = XDocument.Parse(new Regex("<ElementName.*>")
    .Replace(template.ToString(SaveOptions.DisableFormatting), "<ElementName>"));
JJoos
Be careful with your regular expressions. XML is not a regular language so, in general, regular expressions shouldn't be used against XML.
John Saunders
+1  A: 

Here is an example that outputs xml without empty namespaces. Notice the bizarre Linq-centric syntax rootNamespace + "MyElementName", which is the secret. This is the same namespace as the whole document, thus no xmlns addition is necessary. This is concatenating an XNamespace + a string, which is a "+" overload that works for Linq and that Linq knows how to deal with. (Without Linq it could be a compile error to concatenate a string and a non string type). Note this was executed against a C# project file which is a handy Xml file. Output it to a console or a richtextbox control. Then take out the "rootNamespace +" and notice the difference.

        XDocument doc = null;

        using (StreamReader streamReader =
            new StreamReader(@"myXml.csproj"))
        {
            doc = XDocument.Load(streamReader, LoadOptions.None);
        }
        XNamespace rootNamespace = doc.Root.Name.NamespaceName;

        // A search which finds the ItemGroup which has Reference 
        // elements and returns the ItemGroup XElement.
        XElement element = doc.Descendants().Where(p => p.Name.LocalName == "ItemGroup"
            && p.Descendants().First<XElement>().Name.LocalName == "Reference").First<XElement>();

        // Create a completly new element with sub elements.
        XElement referenceElement = new XElement(rootNamespace + "Reference",
            new XElement(rootNamespace + "SpecificVersion", bool.FalseString),
            new XElement(rootNamespace + "HintPath", "THIS IS A HINT PATH"));

       // Add the new element to the main doc, to the end of the Reference elements.
        element.Add(referenceElement);

        // Add an attribute after the fact for effect.
        referenceElement.SetAttributeValue("Include", "THIS IS AN INCLUDE");

        rtb.Text = doc.ToString(SaveOptions.None);
Wray Smallwood
Thank you this looks like a really good solution! I'll try it next time i run in to this problem.
JJoos