Bob Peterson
Bob Peterson

Reputation: 706

How do I compose XDocument and keep the same namespace prefix throughout?

I'm having trouble composing an XDocument which uses two namespaces. When I add XElements created by a different method (which refer to the exact same XNamespace instances), I get a redeclaration of the xmlns with a different prefix. It's perfectly correct XML, but is a bear for human readability.

XDocument xml = new XDocument();
XElement e_graphml = new XElement(ns_graphML + "graphml",
            new XAttribute("xmlns", ns_graphML),
            new XAttribute(XNamespace.Xmlns + "y", ns_yGraphML));
xml.Add(e_graphml);
XElement child = graph.ToX();
e_graphml.Add(child);

The graph object uses my globally available ns_graphML and ns_yGraphML objects, both type XNamespace. Yet the XML I get back serializes to text as:

<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:y="http://www.yworks.com/xml/graphml">
  <graph p3:edgedefault="directed" p3:id="fileReferences" xmlns:p3="http://graphml.graphdrawing.org/xmlns" />
</graphml>

(EDIT) I expect:

<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:y="http://www.yworks.com/xml/graphml">
  <graph edgedefault="directed" id="fileReferences"/>
</graphml>

(/EDIT)

The graph element should inherit the default xmlns once it is added to e_graphml, but apparently these are considered different. Note thate graph.ToX() does not add explicit namespace attributes (xmlns=...) to the returned graph XElement; the XNames in it simply refer to the namespace, like so:

XElement e_graph = new XElement(ns_graphML + "graph",
    new XAttribute(ns_graphML + "edgedefault", "directed"),
    new XAttribute(ns_graphML + "id", Name));

Perhaps this is a duplicate of Force XDocument to not use namespace prefix if namespace is also defined as default, but I'm creating the XDocument entirely in code, not from initial XML text.

Upvotes: 0

Views: 374

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134491

I think this behavior is intended. Attributes without a namespace prefix isn't part of any namespace, not even the default namespace. It needed to put the attribute in that namespace but since it didn't have a prefix to use, it had to create one. I think it'll be easier to just create the document but use explicit prefixes for the namespaces, it'll come out a lot cleaner.

var e_graphml = new XElement(ns_graphML + "graphml",
    new XAttribute(XNamespace.Xmlns + "g", ns_graphML),
    new XAttribute(XNamespace.Xmlns + "y", ns_yGraphML)
);

This will yield xml like so:

<g:graphml xmlns:g="http://graphml.graphdrawing.org/xmlns" xmlns:y="http://www.yworks.com/xml/graphml">
    <g:graph g:edgedefault="directed" g:id="fileReferences" />
</g:graphml>

If you specifically want to have it render the attributes without prefixes, remove the namespace when you generate them. Attributes typically don't need to be namespaced unless explicitly required.

var e_graph = new XElement(ns_graphML + "graph",
    new XAttribute("edgedefault", "directed"),
    new XAttribute("id", Name)
);
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:y="http://www.yworks.com/xml/graphml">
    <graph edgedefault="directed" id="fileReferences" />
</graphml>

Upvotes: 2

Related Questions