Luciano Jeong
Luciano Jeong

Reputation: 335

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#?

Upvotes: 2

Views: 1919

Answers (2)

dbc
dbc

Reputation: 117026

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.

Upvotes: 1

jdweng
jdweng

Reputation: 34421

The Net library want the default namespace (without the prefix) to be the last namespace. I usually just use the Parse method which has less restrictions. See code below :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml = "<foo:document xmlns=\"http://www.example.com/xmlns\" xmlns:foo=\"http://www.example.com/xmlns/foo-version1\">" +
                         "   <foo:bar foo:baz=\"true\" />" +
                         "</foo:document>";

            XDocument doc = XDocument.Parse(xml);
        }
    }
}

Upvotes: 0

Related Questions