[c#] Creating an XmlNode/XmlElement in C# without an XmlDocument?

I have a simple class that essentially just holds some values. I have overridden the ToString() method to return a nice string representation.

Now, I want to create a ToXml() method, that will return something like this:

<Song>
    <Artist>Bla</Artist>
    <Title>Foo</Title>
</Song>

Of course, I could just use a StringBuilder here, but I would like to return an XmlNode or XmlElement, to be used with XmlDocument.AppendChild.

I do not seem to be able to create an XmlElement other than calling XmlDocument.CreateElement, so I wonder if I have just overlooked anything, or if I really either have to pass in either a XmlDocument or ref XmlElement to work with, or have the function return a String that contains the XML I want?

This question is related to c# xml

The answer is


You may want to look at how you can use the built-in features of .NET to serialize and deserialize an object into XML, rather than creating a ToXML() method on every class that is essentially just a Data Transfer Object.

I have used these techniques successfully on a couple of projects but don’t have the implementation details handy right now. I will try to update my answer with my own examples sometime later.

Here's a couple of examples that Google returned:

XML Serialization in .NET by Venkat Subramaniam http://www.agiledeveloper.com/articles/XMLSerialization.pdf

How to Serialize and Deserialize an object into XML http://www.dotnetfunda.com/articles/article98.aspx

Customize your .NET object XML serialization with .NET XML attributes http://blogs.microsoft.co.il/blogs/rotemb/archive/2008/07/27/customize-your-net-object-xml-serialization-with-net-xml-attributes.aspx


You can't return an XmlElement or an XmlNode, because those objects always and only exist within the context of an owning XmlDocument.

XML serialization is a little easier than returning an XElement, because all you have to do is mark properties with attributes and the serializer does all the XML generation for you. (Plus you get deserialization for free, assuming you have a parameterless constructor and, well, a bunch of other things.)

On the other hand, a) you have to create an XmlSerializer to do it, b) dealing with collection properties isn't quite the no-brainer you might like it to be, and c) XML serialization is pretty dumb; you're out of luck if you want to do anything fancy with the XML you're generating.

In a lot of cases, those issues don't matter one bit. I for one would rather mark my properties with attributes than write a method.


I would recommend to use XDoc and XElement of System.Xml.Linq instead of XmlDocument stuff. This would be better and you will be able to make use of the LINQ power in querying and parsing your XML:

Using XElement, your ToXml() method will look like the following:

public XElement ToXml()
{
    XElement element = new XElement("Song",
                        new XElement("Artist", "bla"),
                        new XElement("Title", "Foo"));

    return element;
}

Another option is to pass a delegate to method, which will create an XmlElement. This way the target method won't get access to whole XmlDocument, but will be able to create new elements.


You need Linq - System.Xml.Linq to be precise.

You can create XML using XElement from scratch - that should pretty much sort you out.


XmlNodes come with an OwnerDocument property.

Perhaps you can just do:

//Node is an XmlNode pulled from an XmlDocument
XmlElement e = node.OwnerDocument.CreateElement("MyNewElement");
e.InnerText = "Some value";
node.AppendChild(e);

Why not consider creating your data class(es) as just a subclassed XmlDocument, then you get all of that for free. You don't need to serialize or create any off-doc nodes at all, and you get structure you want.

If you want to make it more sophisticated, write a base class that is a subclass of XmlDocument, then give it basic accessors, and you're set.

Here's a generic type I put together for a project...

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

namespace FWFWLib {
    public abstract class ContainerDoc : XmlDocument {

        protected XmlElement root = null;
        protected const string XPATH_BASE = "/$DATA_TYPE$";
        protected const string XPATH_SINGLE_FIELD = "/$DATA_TYPE$/$FIELD_NAME$";

        protected const string DOC_DATE_FORMAT = "yyyyMMdd";
        protected const string DOC_TIME_FORMAT = "HHmmssfff";
        protected const string DOC_DATE_TIME_FORMAT = DOC_DATE_FORMAT + DOC_TIME_FORMAT;

        protected readonly string datatypeName = "containerDoc";
        protected readonly string execid = System.Guid.NewGuid().ToString().Replace( "-", "" );

        #region startup and teardown
        public ContainerDoc( string execid, string datatypeName ) {
            root = this.DocumentElement;
            this.datatypeName = datatypeName;
            this.execid = execid;
            if( null == datatypeName || "" == datatypeName.Trim() ) {
                throw new InvalidDataException( "Data type name can not be blank" );
            }
            Init();
        }

        public ContainerDoc( string datatypeName ) {
            root = this.DocumentElement;
            this.datatypeName = datatypeName;
            if( null == datatypeName || "" == datatypeName.Trim() ) {
                throw new InvalidDataException( "Data type name can not be blank" );
            }
            Init();
        }

        private ContainerDoc() { /*...*/ }

        protected virtual void Init() {
            string basexpath = XPATH_BASE.Replace( "$DATA_TYPE$", datatypeName );
            root = (XmlElement)this.SelectSingleNode( basexpath );
            if( null == root ) {
                root = this.CreateElement( datatypeName );
                this.AppendChild( root );
            }
            SetFieldValue( "createdate", DateTime.Now.ToString( DOC_DATE_FORMAT ) );
            SetFieldValue( "createtime", DateTime.Now.ToString( DOC_TIME_FORMAT ) );
        }
        #endregion

        #region setting/getting data fields
        public virtual void SetFieldValue( string fieldname, object val ) {
            if( null == fieldname || "" == fieldname.Trim() ) {
                return;
            }
            fieldname = fieldname.Replace( " ", "_" ).ToLower();
            string xpath = XPATH_SINGLE_FIELD.Replace( "$FIELD_NAME$", fieldname ).Replace( "$DATA_TYPE$", datatypeName );
            XmlNode node = this.SelectSingleNode( xpath );
            if( null != node ) {
                if( null != val ) {
                    node.InnerText = val.ToString();
                }
            } else {
                node = this.CreateElement( fieldname );
                if( null != val ) {
                    node.InnerText = val.ToString();
                }
                root.AppendChild( node );
            }
        }

        public virtual string FieldValue( string fieldname ) {
            if( null == fieldname ) {
                fieldname = "";
            }
            fieldname = fieldname.ToLower().Trim();
            string rtn = "";
            XmlNode node = this.SelectSingleNode( XPATH_SINGLE_FIELD.Replace( "$FIELD_NAME$", fieldname ).Replace( "$DATA_TYPE$", datatypeName ) );
            if( null != node ) {
                rtn = node.InnerText;
            }
            return rtn.Trim();
        }

        public virtual string ToXml() {
            return this.OuterXml;
        }

        public override string ToString() {
            return ToXml();
        }
        #endregion

        #region io
        public void WriteTo( string filename ) {
            TextWriter tw = new StreamWriter( filename );
            tw.WriteLine( this.OuterXml );
            tw.Close();
            tw.Dispose();
        }

        public void WriteTo( Stream strm ) {
            TextWriter tw = new StreamWriter( strm );
            tw.WriteLine( this.OuterXml );
            tw.Close();
            tw.Dispose();
        }

        public void WriteTo( TextWriter writer ) {
            writer.WriteLine( this.OuterXml );
        }
        #endregion

    }
}

XmlNodes come with an OwnerDocument property.

Perhaps you can just do:

//Node is an XmlNode pulled from an XmlDocument
XmlElement e = node.OwnerDocument.CreateElement("MyNewElement");
e.InnerText = "Some value";
node.AppendChild(e);

You could return an XmlDocument for the ToXML method in your class, then when you are going to add the Element with the result document just use something like:

XmlDocument returnedDocument = Your_Class.ToXML();

XmlDocument finalDocument = new XmlDocument();
XmlElement createdElement = finalDocument.CreateElement("Desired_Element_Name");
createdElement.InnerXML = docResult.InnerXML;
finalDocument.AppendChild(createdElement);

That way the entire value for "Desired_Element_Name" on your result XmlDocument will be the entire content of the returned Document.

I hope this helps.


You can't return an XmlElement or an XmlNode, because those objects always and only exist within the context of an owning XmlDocument.

XML serialization is a little easier than returning an XElement, because all you have to do is mark properties with attributes and the serializer does all the XML generation for you. (Plus you get deserialization for free, assuming you have a parameterless constructor and, well, a bunch of other things.)

On the other hand, a) you have to create an XmlSerializer to do it, b) dealing with collection properties isn't quite the no-brainer you might like it to be, and c) XML serialization is pretty dumb; you're out of luck if you want to do anything fancy with the XML you're generating.

In a lot of cases, those issues don't matter one bit. I for one would rather mark my properties with attributes than write a method.


From W3C Document Object Model (Core) Level 1 specification (bold is mine):

Most of the APIs defined by this specification are interfaces rather than classes. That means that an actual implementation need only expose methods with the defined names and specified operation, not actually implement classes that correspond directly to the interfaces. This allows the DOM APIs to be implemented as a thin veneer on top of legacy applications with their own data structures, or on top of newer applications with different class hierarchies. This also means that ordinary constructors (in the Java or C++ sense) cannot be used to create DOM objects, since the underlying objects to be constructed may have little relationship to the DOM interfaces. The conventional solution to this in object-oriented design is to define factory methods that create instances of objects that implement the various interfaces. In the DOM Level 1, objects implementing some interface "X" are created by a "createX()" method on the Document interface; this is because all DOM objects live in the context of a specific Document.

AFAIK, you can not create any XmlNode (XmlElement, XmlAttribute, XmlCDataSection, etc) except XmlDocument from a constructor.

Moreover, note that you can not use XmlDocument.AppendChild() for nodes that are not created via the factory methods of the same document. In case you have a node from another document, you must use XmlDocument.ImportNode().


Create a new XmlDocument with the contents you want and then import it into your existing document, by accessing the OwnerDocument property of your existing nodes:

XmlNode existing_node; // of some document, where we don't know necessarily know the XmlDocument...
XmlDocument temp = new XmlDocument();
temp.LoadXml("<new><elements/></new>");
XmlNode new_node = existing_node.OwnerDocument.ImportNode(temp.DocumentElement, true);
existing_node.AppendChild(new_node);

Good luck.


You can't return an XmlElement or an XmlNode, because those objects always and only exist within the context of an owning XmlDocument.

XML serialization is a little easier than returning an XElement, because all you have to do is mark properties with attributes and the serializer does all the XML generation for you. (Plus you get deserialization for free, assuming you have a parameterless constructor and, well, a bunch of other things.)

On the other hand, a) you have to create an XmlSerializer to do it, b) dealing with collection properties isn't quite the no-brainer you might like it to be, and c) XML serialization is pretty dumb; you're out of luck if you want to do anything fancy with the XML you're generating.

In a lot of cases, those issues don't matter one bit. I for one would rather mark my properties with attributes than write a method.


Why not consider creating your data class(es) as just a subclassed XmlDocument, then you get all of that for free. You don't need to serialize or create any off-doc nodes at all, and you get structure you want.

If you want to make it more sophisticated, write a base class that is a subclass of XmlDocument, then give it basic accessors, and you're set.

Here's a generic type I put together for a project...

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

namespace FWFWLib {
    public abstract class ContainerDoc : XmlDocument {

        protected XmlElement root = null;
        protected const string XPATH_BASE = "/$DATA_TYPE$";
        protected const string XPATH_SINGLE_FIELD = "/$DATA_TYPE$/$FIELD_NAME$";

        protected const string DOC_DATE_FORMAT = "yyyyMMdd";
        protected const string DOC_TIME_FORMAT = "HHmmssfff";
        protected const string DOC_DATE_TIME_FORMAT = DOC_DATE_FORMAT + DOC_TIME_FORMAT;

        protected readonly string datatypeName = "containerDoc";
        protected readonly string execid = System.Guid.NewGuid().ToString().Replace( "-", "" );

        #region startup and teardown
        public ContainerDoc( string execid, string datatypeName ) {
            root = this.DocumentElement;
            this.datatypeName = datatypeName;
            this.execid = execid;
            if( null == datatypeName || "" == datatypeName.Trim() ) {
                throw new InvalidDataException( "Data type name can not be blank" );
            }
            Init();
        }

        public ContainerDoc( string datatypeName ) {
            root = this.DocumentElement;
            this.datatypeName = datatypeName;
            if( null == datatypeName || "" == datatypeName.Trim() ) {
                throw new InvalidDataException( "Data type name can not be blank" );
            }
            Init();
        }

        private ContainerDoc() { /*...*/ }

        protected virtual void Init() {
            string basexpath = XPATH_BASE.Replace( "$DATA_TYPE$", datatypeName );
            root = (XmlElement)this.SelectSingleNode( basexpath );
            if( null == root ) {
                root = this.CreateElement( datatypeName );
                this.AppendChild( root );
            }
            SetFieldValue( "createdate", DateTime.Now.ToString( DOC_DATE_FORMAT ) );
            SetFieldValue( "createtime", DateTime.Now.ToString( DOC_TIME_FORMAT ) );
        }
        #endregion

        #region setting/getting data fields
        public virtual void SetFieldValue( string fieldname, object val ) {
            if( null == fieldname || "" == fieldname.Trim() ) {
                return;
            }
            fieldname = fieldname.Replace( " ", "_" ).ToLower();
            string xpath = XPATH_SINGLE_FIELD.Replace( "$FIELD_NAME$", fieldname ).Replace( "$DATA_TYPE$", datatypeName );
            XmlNode node = this.SelectSingleNode( xpath );
            if( null != node ) {
                if( null != val ) {
                    node.InnerText = val.ToString();
                }
            } else {
                node = this.CreateElement( fieldname );
                if( null != val ) {
                    node.InnerText = val.ToString();
                }
                root.AppendChild( node );
            }
        }

        public virtual string FieldValue( string fieldname ) {
            if( null == fieldname ) {
                fieldname = "";
            }
            fieldname = fieldname.ToLower().Trim();
            string rtn = "";
            XmlNode node = this.SelectSingleNode( XPATH_SINGLE_FIELD.Replace( "$FIELD_NAME$", fieldname ).Replace( "$DATA_TYPE$", datatypeName ) );
            if( null != node ) {
                rtn = node.InnerText;
            }
            return rtn.Trim();
        }

        public virtual string ToXml() {
            return this.OuterXml;
        }

        public override string ToString() {
            return ToXml();
        }
        #endregion

        #region io
        public void WriteTo( string filename ) {
            TextWriter tw = new StreamWriter( filename );
            tw.WriteLine( this.OuterXml );
            tw.Close();
            tw.Dispose();
        }

        public void WriteTo( Stream strm ) {
            TextWriter tw = new StreamWriter( strm );
            tw.WriteLine( this.OuterXml );
            tw.Close();
            tw.Dispose();
        }

        public void WriteTo( TextWriter writer ) {
            writer.WriteLine( this.OuterXml );
        }
        #endregion

    }
}

From W3C Document Object Model (Core) Level 1 specification (bold is mine):

Most of the APIs defined by this specification are interfaces rather than classes. That means that an actual implementation need only expose methods with the defined names and specified operation, not actually implement classes that correspond directly to the interfaces. This allows the DOM APIs to be implemented as a thin veneer on top of legacy applications with their own data structures, or on top of newer applications with different class hierarchies. This also means that ordinary constructors (in the Java or C++ sense) cannot be used to create DOM objects, since the underlying objects to be constructed may have little relationship to the DOM interfaces. The conventional solution to this in object-oriented design is to define factory methods that create instances of objects that implement the various interfaces. In the DOM Level 1, objects implementing some interface "X" are created by a "createX()" method on the Document interface; this is because all DOM objects live in the context of a specific Document.

AFAIK, you can not create any XmlNode (XmlElement, XmlAttribute, XmlCDataSection, etc) except XmlDocument from a constructor.

Moreover, note that you can not use XmlDocument.AppendChild() for nodes that are not created via the factory methods of the same document. In case you have a node from another document, you must use XmlDocument.ImportNode().


I would recommend to use XDoc and XElement of System.Xml.Linq instead of XmlDocument stuff. This would be better and you will be able to make use of the LINQ power in querying and parsing your XML:

Using XElement, your ToXml() method will look like the following:

public XElement ToXml()
{
    XElement element = new XElement("Song",
                        new XElement("Artist", "bla"),
                        new XElement("Title", "Foo"));

    return element;
}

Another option is to pass a delegate to method, which will create an XmlElement. This way the target method won't get access to whole XmlDocument, but will be able to create new elements.


From W3C Document Object Model (Core) Level 1 specification (bold is mine):

Most of the APIs defined by this specification are interfaces rather than classes. That means that an actual implementation need only expose methods with the defined names and specified operation, not actually implement classes that correspond directly to the interfaces. This allows the DOM APIs to be implemented as a thin veneer on top of legacy applications with their own data structures, or on top of newer applications with different class hierarchies. This also means that ordinary constructors (in the Java or C++ sense) cannot be used to create DOM objects, since the underlying objects to be constructed may have little relationship to the DOM interfaces. The conventional solution to this in object-oriented design is to define factory methods that create instances of objects that implement the various interfaces. In the DOM Level 1, objects implementing some interface "X" are created by a "createX()" method on the Document interface; this is because all DOM objects live in the context of a specific Document.

AFAIK, you can not create any XmlNode (XmlElement, XmlAttribute, XmlCDataSection, etc) except XmlDocument from a constructor.

Moreover, note that you can not use XmlDocument.AppendChild() for nodes that are not created via the factory methods of the same document. In case you have a node from another document, you must use XmlDocument.ImportNode().


Create a new XmlDocument with the contents you want and then import it into your existing document, by accessing the OwnerDocument property of your existing nodes:

XmlNode existing_node; // of some document, where we don't know necessarily know the XmlDocument...
XmlDocument temp = new XmlDocument();
temp.LoadXml("<new><elements/></new>");
XmlNode new_node = existing_node.OwnerDocument.ImportNode(temp.DocumentElement, true);
existing_node.AppendChild(new_node);

Good luck.


I would recommend to use XDoc and XElement of System.Xml.Linq instead of XmlDocument stuff. This would be better and you will be able to make use of the LINQ power in querying and parsing your XML:

Using XElement, your ToXml() method will look like the following:

public XElement ToXml()
{
    XElement element = new XElement("Song",
                        new XElement("Artist", "bla"),
                        new XElement("Title", "Foo"));

    return element;
}

You need Linq - System.Xml.Linq to be precise.

You can create XML using XElement from scratch - that should pretty much sort you out.


You could return an XmlDocument for the ToXML method in your class, then when you are going to add the Element with the result document just use something like:

XmlDocument returnedDocument = Your_Class.ToXML();

XmlDocument finalDocument = new XmlDocument();
XmlElement createdElement = finalDocument.CreateElement("Desired_Element_Name");
createdElement.InnerXML = docResult.InnerXML;
finalDocument.AppendChild(createdElement);

That way the entire value for "Desired_Element_Name" on your result XmlDocument will be the entire content of the returned Document.

I hope this helps.


XmlDocumnt xdoc = new XmlDocument;
XmlNode songNode = xdoc.CreateNode(XmlNodeType.Element, "Song", schema)
xdoc.AppendChild.....

You can't return an XmlElement or an XmlNode, because those objects always and only exist within the context of an owning XmlDocument.

XML serialization is a little easier than returning an XElement, because all you have to do is mark properties with attributes and the serializer does all the XML generation for you. (Plus you get deserialization for free, assuming you have a parameterless constructor and, well, a bunch of other things.)

On the other hand, a) you have to create an XmlSerializer to do it, b) dealing with collection properties isn't quite the no-brainer you might like it to be, and c) XML serialization is pretty dumb; you're out of luck if you want to do anything fancy with the XML you're generating.

In a lot of cases, those issues don't matter one bit. I for one would rather mark my properties with attributes than write a method.


XmlDocumnt xdoc = new XmlDocument;
XmlNode songNode = xdoc.CreateNode(XmlNodeType.Element, "Song", schema)
xdoc.AppendChild.....