41

I'm trying to generate the following xml element using C#.

<Foo xmlns="http://schemas.foo.com" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://schemas.foo.com
 http://schemas.foo.com/Current/xsd/Foo.xsd">

The problem that I'm having is that I get the exception:

The prefix " cannot be redefined from " to within the same start element tag.

This is my c# code:

XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XElement foo = new XElement("Foo", new XAttribute("xmlns", "http://schemas.foo.com"),
                                   new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
                                   new XAttribute(xsi + "schemaLocation", "http://schemas.foo.com http://schemas.foo.com/Current/xsd/Foo.xsd"));

How can I fix this? I'm trying to send the generated xml as the body of a SOAP message and I need it to be in this format for the receiver.

EDIT: I found my answer on another question. Controlling the order of XML namepaces

stop-cran
  • 4,229
  • 2
  • 30
  • 47
Rainbacon
  • 933
  • 1
  • 16
  • 24
  • 4
    Prompted by the fact that there is a new answer to this question if you found the answer you should answer this question with the fix that worked for you rather than just editing the question to say you have an answer. Unless this question is actually a duplicate of the other in which case it should be marked as such but it doesn't seem to be an exact duplicate. – Chris Nov 03 '14 at 12:50
  • I found a solution to this problem here... [https://www.guyellisrocks.com/2009/03/the-prefix-cannot-be-redefined-from.html]. It seemed like I needed to define the default namespace when the XDoc was defined. HTH. – Steve Hibbert Jul 18 '19 at 08:07

3 Answers3

37

You need to indicate that the element Foo is part of the namespace http://schemas.foo.com. Try this:

XNamespace xNamespace = "http://schemas.foo.com";    
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XElement foo = new XElement(
    xNamespace + "Foo", 
    new XAttribute("xmlns", "http://schemas.foo.com"),
    new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
    new XAttribute(xsi + "schemaLocation", "http://schemas.foo.com http://schemas.foo.com/Current/xsd/Foo.xsd")
    );
stop-cran
  • 4,229
  • 2
  • 30
  • 47
Jose M.
  • 1,296
  • 17
  • 22
11

I was getting this error when creating an XDocument. After a lot of googling I found this article:

http://www.mikesdotnetting.com/Article/111/RSS-Feeds-and-Google-Sitemaps-for-ASP.NET-MVC-with-LINQ-To-XML

There just happens to be an explanation part way through the doc, that I was lucky enough to spot.

The key point is that your code should let the XDocument handle the xmlns attribute. When creating an XElement, your first instinct would be to set the namespace attribute like all the rest, by adding an attribute "xmlns" and setting it to a value.

Instead, you should create an XNamespace variable, and use that XNamespace variable when defining the XElement. This will effectively add an XAttribute to your element for you.

When you add an xmlns attribute yourself, you are telling the XElement creation routine to create an XElement in no namespace, and then to change the namespace using the reserved xmlns attribute. You are contradicting yourself. The error says "You cannot set the namespace to empty, and then set the namespace again to something else in the same tag, you numpty."

The function below illustrates this...

    private static void Test_Namespace_Error(bool doAnError)
    {
        XDocument xDoc = new XDocument();
        string ns = "http://mynamespace.com";
        XElement xEl = null;
        if (doAnError)
        {
            // WRONG: This creates an element with no namespace and then changes the namespace
            xEl = new XElement("tagName", new XAttribute("xmlns", ns));
        }
        else
        {
            // RIGHT: This creates an element in a namespace, and implicitly adds an xmlns tag
            XNamespace xNs = ns;
            xEl = new XElement(xNs + "tagName");
        }

        xDoc.Add(xEl);
        Console.WriteLine(xDoc.ToString());
    }
Steve Hibbert
  • 2,045
  • 4
  • 30
  • 49
  • This is great! Apparently it has one huge drawback though: Doing this on the root only anyway force-adds `xmlns=""` to all other sub `XElement`s as well .. so we will have to either pass in this namespace to ... everything - or find a way to skip this force added empty namespace everywhere – derHugo Aug 04 '22 at 09:41
  • I thought the root having the namespace, and all sub elements have no namespace, would make all the sub elements inherit the root's namespace? – Steve Hibbert Aug 05 '22 at 10:37
  • 1
    exatcly this would happen ... however `XDocument` (at least for) automatically added `xmlns=""` to all childs of the root as soon as I added the samespace to the root using your method ... for now I solved it by simply passing on the namespace into each and every `XElement` which results in the file as you describe it: `xmlns` added only to the root, all others do not have the attribute ... would be nice though if there was an option to make it behave different in the first place – derHugo Aug 05 '22 at 13:53
  • Yes, I would maybe set a class or global variable (sacrilege!) to hold the preferred namespace, to avoid having to pass it around, but whatever works for you is good. Hopefully this helps others work around this annoying issue, thanks. – Steve Hibbert Aug 08 '22 at 10:05
0

Others explain why this is happening but it still took me a while to work out how to fix it for me. I was trying to add some external XML to an XML document.

What finally worked for me was:

    ElementTree.register_namespace("mstts", "https://www.w3.org/2001/mstts")
    ElementTree.register_namespace("", "http://www.w3.org/2001/10/synthesis")
    xml_body = ElementTree.fromstring(
        '<speak version="1.0"'
        '  xmlns:mstts="https://www.w3.org/2001/mstts"'
        '  xmlns="http://www.w3.org/2001/10/synthesis"'
        f' xml:lang="{locale}">'
        f'  <voice name="{azure_voice}">'
        '       <mstts:silence type="Leading" value="0" />'
        '           <prosody rate="-10.00%">'
        f'              {utterance}'
        '           </prosody>'
        '       <mstts:silence type="Tailing" value="0" />'
        '   </voice>'
        '</speak>'
ostergaard
  • 3,377
  • 2
  • 30
  • 40