Search code examples
c#xmlxmldocument

Is it possible to create an XmlElement with two xml namespaces?


I have to generate XML like the below:

<foo:document xmlns="http://www.example.com/xmlns" xmlns:foo="http://www.example.com/xmlns/foo-version1">
    <foo:bar foo:baz="true" />
</foo:document>

How can I generate this document with System.Xml.XmlDocument in c#?


Solution

  • You can do this as follows:

    var fooNs = "http://www.example.com/xmlns/foo-version1";
    var defNs = "http://www.example.com/xmlns";
    
    var doc = new XmlDocument();
    
    // Create and add the root element
    var root = doc.CreateElement("foo", "document", fooNs);
    doc.AppendChild(root);
    
    // Add the default namespace (do note the root element is not in this namespace)
    var defAttr = doc.CreateAttribute("xmlns");
    defAttr.Value = defNs;
    root.Attributes.Append(defAttr);
    
    // Create the <foo:bar> element
    var bar = doc.CreateElement("foo", "bar", fooNs);
    var bazAttr = doc.CreateAttribute("foo", "baz", fooNs);
    bazAttr.Value = XmlConvert.ToString(true);
    bar.Attributes.Append(bazAttr);
    
    // Add it to the root
    root.AppendChild(bar);
    

    Notes:

    • When creating XmlElement and XmlAttribute nodes in a namespace, always prefer to use the Create() overloads that take a prefix, a localName and a namespaceURI:


      From a semantic point of view, what really matters is the node local name and namespace; the prefix is just a lookup to find a namespace declaration in scope.

    • Notice I didn't explicitly add the xmlns:foo="http://www.example.com/xmlns/foo-version1" attribute? It is unnecessary to do this since the root element was created using the required namespace and prefix via doc.CreateElement("foo", "document", fooNs). The framework (XmlWriter) will automatically emit the xmlns:foo attribute as it writes the XmlDocument to XML.

      If for some reason you need to explicitly create the namespace attribute, you can do it as follows:

      // The following is redundant as the framework (XmlWriter) will add the necessary
      // xmlns:foo attribute as the XmlDocument is being written.  If you need to do it anway 
      // (e.g. to control the order) you can do it as follows.
      // (But note that XML attributes are unordered according to the XML specification, for details
      // see https://stackoverflow.com/questions/33746224/in-xml-is-the-attribute-order-important)
      var xmlnsNs = "http://www.w3.org/2000/xmlns/";
      
      var fooAttr = doc.CreateAttribute("xmlns", "foo", xmlnsNs);
      fooAttr.Value = fooNs;
      root.Attributes.Append(fooAttr);
      

    Demo fiddle #1 here.

    Incidentally, as written in comments, it's much easier to do this with LINQ to XML:

    XNamespace fooNs = "http://www.example.com/xmlns/foo-version1";
    XNamespace defNs = "http://www.example.com/xmlns";
    
    var root = new XElement(fooNs + "document"
                            // Add the namespace declarations with your desired prefixes.  Be sure to pass them into the constructor.
                            , new XAttribute("xmlns", defNs.ToString())
                            , new XAttribute(XNamespace.Xmlns + "foo", fooNs.ToString())
                            // And add any required content.  The content can be passed into the constructor, or added later. 
                            , new XElement(fooNs + "bar", new XAttribute(fooNs + "baz", true)));
    

    Notes:

    • With LINQ to XML you never need to worry about the namespace prefix of an XElement or XAttribute. Just create them with the correct namespace and local name as encapsulated by XName. The framework (XmlWriter) will automatically emit all necessary namespace attributes as it writes.

      But if you do need to configure namespaces for some reason you can construct appropriate XAttribute objects and then pass them into the XElement constructor.

    • For further reading see How to: Create a Document with Namespaces (C#) (LINQ to XML).

    Demo fiddle #2 here.