Creating an XmlNode / XmlElement in C # without an XmlDocument?

I have a simple class that essentially just contains some values. I overridden the ToString() method to return a beautiful 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 StringBuilder here, but I would like to return the XmlNode or XmlElement that will be used with XmlDocument.AppendChild .

It seems I can’t create an XmlElement other than calling XmlDocument.CreateElement , so I wonder if I have missed anything at all, or if I really need to go through either XmlDocument or ref XmlElement to work or the function returns a string containing XML. which i want?

+42
c # xml
Oct 18 '08 at 20:07
source share
11 answers

You can see how you can use the .NET built-in functions to serialize and deserialize an object in XML, instead of creating a ToXML() method for each class, which is essentially a data transfer object.

I have successfully used these methods in several projects, but now there is no implementation data. I will try to update my answer with my own examples later.

Here are some examples Google returned:

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

Serializing and deserializing an object in XML http://www.dotnetfunda.com/articles/article98.aspx

Configure XML serialization of an XML object 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

+13
18 Oct '08 at 22:28
source share

I would recommend using XDoc and XElement of System.Xml.Linq instead of XmlDocument. That would be better, and you can use LINQ's capabilities for querying and parsing XML:

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

 public XElement ToXml() { XElement element = new XElement("Song", new XElement("Artist", "bla"), new XElement("Title", "Foo")); return element; } 
+40
Oct 18 '08 at 21:08
source share

From the W3C, the specification of the Document Object Model (Core) level 1 (bold mine):

Most of the APIs defined by this specification are interfaces rather than classes. This means that the actual implementation only requires exposing the methods with specific names and the specified operation, and not actually introducing classes that correspond directly to the interfaces. This allows you to implement the DOM API as a thin veneer on top of the application legacy with its own structure data or on top of new applications with a different Hierarchy class. It also means that ordinary constructors (in Java or C ++) cannot be used to create DOMs, since the objects that need to be built may have little to do with DOM interfaces . The usual solution to this in object-oriented design is to define factory methods that instantiate objects that implement various interfaces. In DOM Level 1, objects that implement some interface β€œX” create the createX () method in the document interface; this is because all DOM objects live in the context of a specific document .

AFAIK, you cannot create an XmlNode ( XmlElement, XmlAttribute, XmlCDataSection , etc.) except for the XmlDocument from the constructor.

Also, note that you cannot use XmlDocument.AppendChild() for nodes that are not created using the factory methods of the same document. If you have a node from another document, you should use XmlDocument.ImportNode() .

+15
Oct 18 '08 at 21:07
source share

XmlNodes come with the 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); 
+8
25 Oct
source share

You can return an XmlDocument for the ToXML method in your class, and then when you are going to add an element with the resulting 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 "Desired_Element_Name" value in your XmlDocument result will be the full content of the returned document.

Hope this helps.

+4
Jan 28 '10 at 3:36
source share

Create a new XmlDocument with the desired content and then import it into an existing document, gaining access to the OwnerDocument property of 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.

+4
Feb 16 2018-12-12T00:
source share

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

You can create XML using XElement from scratch - this will greatly help you.

+2
Oct 18 '08 at 21:04
source share

Another option is to pass the delegate to the method that will create the XmlElement. Thus, the target method will not gain access to the entire XmlDocument, but will be able to create new elements.

+2
Apr 09 '12 at 18:07
source share

Why not consider creating your own data classes as soon as you subclass XmlDocument, then you will get all this for free. You do not need to serialize or create any non-core nodes at all, and you get the right structure.

If you want to make it more complex, write a base class that is a subclass of XmlDocument, then give it base accessors and you are set up.

Here is the general type that I put together for the 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 } } 
+2
Oct 10 '13 at 15:30
source share

You cannot return an XmlElement or XmlNode because these objects always exist and exist only in the context of the owner of the XmlDocument .

Serializing XML is a bit simpler than returning an XElement , because all you have to do is mark the properties with attributes, and the serializer does all the XML generation for you. (In addition, you get free deserialization, assuming you have a constructor without parameters and, well, a bunch of other things.)

On the other hand, a) you need to create an XmlSerializer to do this, b) working with collection properties is not entirely clear to you, and c) XML serialization is pretty dumb; you're out of luck if you want to do something interesting with the XML you create.

In many cases, these problems do not matter. I would rather label my properties with attributes rather than write a method.

+1
Oct 19 '08 at 6:25
source share
 XmlDocumnt xdoc = new XmlDocument; XmlNode songNode = xdoc.CreateNode(XmlNodeType.Element, "Song", schema) xdoc.AppendChild..... 
-2
Aug 07 2018-12-12T00:
source share



All Articles