Retrocoder
Retrocoder

Reputation: 4703

Can't add namespace to XML at runtime

I have an XML file that I need to apply a namespace to at runtime. I’ve searched the net and most examples seem to suggest using the “SetAttributeValue” function. When I use the code below it throws an exception when I try to “ToString()” with the following error:

The prefix '' cannot be redefined from '' to 'http://schemas.datacontract.org/2004/07/' within the same start element tag.

Any ideas what is going wrong?

XDocument data = XDocument.Parse("<Root><Stuff>Test</Stuff></Root>");

string ns = "http://schemas.datacontract.org/2004/07/";

data.Root.SetAttributeValue("xmlns",ns);

SaveFile(data.ToString());

Upvotes: 1

Views: 2203

Answers (5)

Rusty
Rusty

Reputation: 3268

A little late to the party...

XNamespace ns = "http://schemas.datacontract.org/2004/07/"; 
XDocument xdoc = XDocument.Parse("<Root><Stuff>Test</Stuff></Root>");
foreach (var node in xdoc.Descendants()) { node.Name = ns + node.Name.LocalName; }
xdoc.Dump();

<Root xmlns="http://schemas.datacontract.org/2004/07/">
  <Stuff>Test</Stuff>
</Root> 

Upvotes: 2

Mike
Mike

Reputation: 31

The default namespace is actually intrinsic to the XElement and it won't let you redefine it by manipulating the attributes. The namespace for an element is exposed as part of it's XName. So to change the namespace of an element you have to rename it.

XDocument data = XDocument.Parse("<Root><Stuff>Test</Stuff></Root>");

XNamespace ns = "http://schemas.datacontract.org/2004/07/";

data.Root.Name = ns + data.Root.Name.LocalName;

Upvotes: 1

armannvg
armannvg

Reputation: 1712

Those attributes were also bugging me some time ago. I solved it by using the XNamespace class while creating a simple podcast. Following is a sample code from my app:

XDocument xmlDocument = new XDocument(
                new XDeclaration("1.0", "utf-8", "yes")
                );

XNamespace itunesNamespace = "http://www.itunes.com/dtds/podcast-1.0.dtd";
XElement xmlRssElement = new XElement("rss", new XAttribute(XNamespace.Xmlns + "itunes", itunesNamespace), new XAttribute("version", "2.0"));

XElement xmlChannelElement = new XElement("channel",
                             new XElement("title", "title"), 
                             new XElement(itunesNamespace + "explicit", "No"));

xmlRssElement.Add(xmlChannelElement);
xmlDocument.Add(xmlRssElement);
xmlDocument.Save(@"sample-" + DateTime.Now.Ticks + ".xml");

Note that some code has been removed for clarification

You can get your original document by using XDocument.Parse() and from there add the namespace dynamically like is done in my code before saving the document

Upvotes: 0

Tomalak
Tomalak

Reputation: 338138

Do an XSLT transformation:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="your.target.default.namespace"
>
  <!-- 
    the "identity template" copies everything verbatim 
  -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <!-- 
    this template creates new elements that 
    are in "your.target.default.namespace"
    by default
  -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="node() | @*" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

The above takes a namespace-free input document, and copies it. Only element nodes are re-created (by the second template).

Re-creation of element nodes causes them to be in the namespace the XSLT stylesheet is in, here it is "your.target.default.namespace".

With your example, I would get:

<Root xmlns="http://schemas.datacontract.org/2004/07/">
  <Stuff>Test</Stuff>
</Root>

Upvotes: 1

Per Erik Stendahl
Per Erik Stendahl

Reputation: 883

You can't do that. Namespaces are fundamental to the DOM. The only way I can think of right now is to add it using String.Replace on the entire XML text and then reparse the result.

Upvotes: 0

Related Questions