Zaha
Zaha

Reputation: 946

XNamespace and XElement add an empty xmlns attribute on the first child element

I am trying to create the following XML string using XElement

<Issue xmlns="http://tempuri.org/">
    <p>
        <Nombre>no</Nombre>
        <Descripcion>asdf</Descripcion>
    </p>
</Issue>

I've tried the following code, but this approach adds an empty xmlns attribute to the p element, which I don't want:

var ns = XNamespace.Get("http://tempuri.org/");

XElement e = new XElement(ns + "Issues",
                          new XElement("p", new XElement("Nombre", "nme"), 
                                            new XElement("Descripcion", "dsc")));

How can I prevent this issue?

NOTE:

I cannot use XElement.Parse like this because I need to build my soap request body dynamically:

var body = XElement.Parse("<Issue xmlns=\"http://tempuri.org/\"><p><Nombre>no</Nombre><Descripcion>asdf</Descripcion></p></Issue>");

I can't do this with a web service reference because is there an error when there exists a reference from Xamarin.


For now I am using the following workaround, but it is not the best solution, I guess:

var xdoc = new XmlDocument();
var xissue = xdoc.CreateElement("Issue");

var attr = xdoc.CreateAttribute("xmlns");
attr.Value = "http://tempuri.org/";
xissue.Attributes.Append(attr);

var xp = xdoc.CreateElement("p");
xissue.AppendChild(xp);

var xnombre = xdoc.CreateElement("Nombre");
xnombre.InnerText = "any value";
xp.AppendChild(xnombre);

var xdescription = xdoc.CreateElement("Descripcion");
xdescription.InnerText = "any value";
xp.AppendChild(xdescription);

var e = XElement.Parse(xissue.OuterXml);

Upvotes: 2

Views: 1755

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129687

In XML, when an element does not have a namespace specified, then it inherits the namespace of its nearest ancestor that has a namespace. So, in your sample XML, the p element and its children are actually all in the same namespace as Issue, because they do not have an xmlns attribute while Issue does.

To create this same structure using XElement, then, you need to make sure that all the elements specify the same namespace as Issue:

var ns = XNamespace.Get("http://tempuri.org/");

XElement e = new XElement(ns + "Issue",
                          new XElement(ns + "p", new XElement(ns + "Nombre", "nme"),
                                                 new XElement(ns + "Descripcion", "dsc")));

XElement is smart enough to recognize that when it is converted to string it does not need to repeat the xmlns attribute if it matches that of its parent.

Fiddle: https://dotnetfiddle.net/QzYPoK

Conversely, if you just specify a namespace on the outer XElement but not on the inner ones, you are actually saying that you don't want the inner elements to have a namespace at all. And so that results in an empty xmlns attribute on the first child element: it is effectively "opting out" of the parent namespace.

Upvotes: 2

Related Questions