greenfeet
greenfeet

Reputation: 677

How do I create an XElement that contains a prefix without a wrapper?

I'm trying to create a simple empty XElement like this:

<dyn:Positions>
   <Vector2-Array>
   </Vector2-Array>
</dyn:Positions>

I have the namespace defined above:

XNamespace dyn = "https://www.abc.at/dyn";

But when I create the XElement:

XElement positions = new XElement(dyn + "Positions", new XElement("Vector2-Array"));

It comes out like this:

<Positions xmlns="dyn">
  <Vector2-Array xmlns="" />
</Positions>

Is that possible without wrapping it in another XElement? Because I need this element to be appended in another document later, after more elements are added inside.

Upvotes: 0

Views: 492

Answers (2)

Matt Hogan-Jones
Matt Hogan-Jones

Reputation: 3103

Because you're not adding your namespace declaration, the dyn namespace becomes the default.

Then, when you add the child element without a namespace, a namespace declaration with no namespace has to be added to indicate it is not within the default namespace.

If your dyn namespace is not meant to be the default namespace, try the following code:

XNamespace dyn = "https://www.abc.at/dyn";

XElement positions = new XElement(
    dyn + "Positions",
    new XAttribute(XNamespace.Xmlns + "dyn", "https://www.abc.at/dyn"),
new XElement("Vector2-Array"));

This produces the following output:

<dyn:Positions xmlns:dyn="https://www.abc.at/dyn">
  <Vector2-Array />
</dyn:Positions>

Note that when you start appending this element to other documents, you may get more behaviour similar to your original problem if there's any mismatches of namespaces.

The OP has specifically brought up the subject of appending this element to another element that also contains the namespace declaration.

I've created this code to test:

        XNamespace dyn = "https://www.abc.at/dyn";

        XElement positions = new XElement(
            dyn + "Positions",
            new XAttribute(XNamespace.Xmlns + "dyn", "https://www.abc.at/dyn"),
        new XElement("Vector2-Array"));

        XElement root = new XElement(
            dyn + "root",
            new XAttribute(XNamespace.Xmlns + "dyn", "https://www.abc.at/dyn"));

        root.Add(positions);

When using the debugger, the XML of the root element after adding Positions is this:

<dyn:root xmlns:dyn="https://www.abc.at/dyn">
  <dyn:Positions xmlns:dyn="https://www.abc.at/dyn">
    <Vector2-Array />
  </dyn:Positions>
</dyn:root>

So the namespace declaration is duplicated.

However, there is a SaveOption of OmitDuplicateNamespaces that can be used when saving or formatting the XML to string:

Console.WriteLine(root.ToString(SaveOptions.OmitDuplicateNamespaces));

The resulting output of this is as below:

<dyn:root xmlns:dyn="https://www.abc.at/dyn">
  <dyn:Positions>
    <Vector2-Array />
  </dyn:Positions>
</dyn:root>

Because the duplicate namespace declarations effectively do nothing (even though they're ugly) they can be removed this way, if the displaying of the XML is the important thing.

Functionally, having duplicated namespace declarations doesn't actually do anything as long as they match.

Upvotes: 1

Henk Holterman
Henk Holterman

Reputation: 273244

I think you want Vector2-Array to be in the same namespace as Positions, and then you don't see it in the output:

XElement positions = new XElement(dyn + "Positions", 
       new XElement(dyn + "Vector2-Array"));

this gives

<Positions xmlns="https://www.abc.at/dyn">
  <Vector2-Array />
</Positions>

the dyn: notation is just a shorthand, it should not matter when you later merge this in some parent XML. You should be very sure about which namespace everything belongs to.

Upvotes: 1

Related Questions