How to Build Xml in C#

How can I build XML in C#?

It depends on the scenario. XmlSerializer is certainly one way and has the advantage of mapping directly to an object model. In .NET 3.5, XDocument, etc. are also very friendly. If the size is very large, then XmlWriter is your friend.

For an XDocument example:

Console.WriteLine(
new XElement("Foo",
new XAttribute("Bar", "some & value"),
new XElement("Nested", "data")));

Or the same with XmlDocument:

XmlDocument doc = new XmlDocument();
XmlElement el = (XmlElement)doc.AppendChild(doc.CreateElement("Foo"));
el.SetAttribute("Bar", "some & value");
el.AppendChild(doc.CreateElement("Nested")).InnerText = "data";
Console.WriteLine(doc.OuterXml);

If you are writing a large stream of data, then any of the DOM approaches (such as XmlDocument/XDocument, etc.) will quickly take a lot of memory. So if you are writing a 100 MB XML file from CSV, you might consider XmlWriter; this is more primitive (a write-once firehose), but very efficient (imagine a big loop here):

XmlWriter writer = XmlWriter.Create(Console.Out);
writer.WriteStartElement("Foo");
writer.WriteAttributeString("Bar", "Some & value");
writer.WriteElementString("Nested", "data");
writer.WriteEndElement();

Finally, via XmlSerializer:

[Serializable]
public class Foo
{
[XmlAttribute]
public string Bar { get; set; }
public string Nested { get; set; }
}
...
Foo foo = new Foo
{
Bar = "some & value",
Nested = "data"
};
new XmlSerializer(typeof(Foo)).Serialize(Console.Out, foo);

This is a nice model for mapping to classes, etc.; however, it might be overkill if you are doing something simple (or if the desired XML doesn't really have a direct correlation to the object model). Another issue with XmlSerializer is that it doesn't like to serialize immutable types : everything must have a public getter and setter (unless you do it all yourself by implementing IXmlSerializable, in which case you haven't gained much by using XmlSerializer).

How to create XML in C#


//Create XmlDocument
XmlDocument xmlDoc = new XmlDocument();

//Create the root element
XmlNode outputsElement = xmlDoc.CreateElement("outputs");

//Create the child element
XmlElement Element = xmlDoc.CreateElement("output");

//Create "name" Attribute
XmlAttribute nameAtt = xmlDoc.CreateAttribute("name");
Element.Attributes.Append(nameAtt);

//Create "value" Attribute
XmlAttribute valueAtt = xmlDoc.CreateAttribute("value");
Element.Attributes.Append(valueAtt);

//Create "type" Attribute
XmlAttribute typeAtt = xmlDoc.CreateAttribute("type");
Element.Attributes.Append(typeAtt);

//Append child element into root element
outputsElement.AppendChild(Element);

and to return it as string:
xmlDoc.OuterXml;

Create XML file using c# like below format

You can create your required XML using the XML Document Object Model as follows:

var soapNs = @"http://schemas.xmlsoap.org/soap/envelope/";
var bodyNs = @"";

var doc = new XmlDocument();
var root = doc.AppendChild(doc.CreateElement("SOAP-ENV", "Envelope", soapNs));
var body = root.AppendChild(doc.CreateElement("SOAP-ENV", "Body", soapNs));

body.AppendChild(doc.CreateElement("", "AddressLine1", bodyNs)).InnerText = "50 W TOWN ST";
body.AppendChild(doc.CreateElement("", "AddressLine2", bodyNs)).InnerText = "STE 400";
body.AppendChild(doc.CreateElement("", "City", bodyNs)).InnerText = "COLUMBUS";
body.AppendChild(doc.CreateElement("", "State", bodyNs)).InnerText = "OH";
body.AppendChild(doc.CreateElement("", "Zip", bodyNs)).InnerText = "43215";
body.AppendChild(doc.CreateElement("", "Zip4", bodyNs)).InnerText = "";

Using this approach, the following XML is generated:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<AddressLine1>50 W TOWN ST</AddressLine1>
<AddressLine2>STE 400</AddressLine2>
<City>COLUMBUS</City>
<State>OH</State>
<Zip>43215</Zip>
<Zip4></Zip4>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Notes:

  1. A well-formed XML document must have one and only one root element. In the initial version of your question, you try to add multiple nodes directly to the XmlDocument doc:

    doc.AppendChild(docNode);
    // Snip some code
    doc.AppendChild(AddressRequestNode);

    Attempting to do this causes the This document already has a 'DocumentElement' node. exception to be thrown.

  2. Your XML document has elements in two namespaces: http://schemas.xmlsoap.org/soap/envelope/ and the empty namespace. In situations such as this, it's easiest to use the XmlDocument.CreateElement(string prefix, string localName, string namespaceURI) API and always explicitly specify the namespace URI, rather than simply specifying the namespace lookup prefix and hoping you had correctly initialized the corresponding xmlns: prefix value earlier.

    In the sample XML, the Envelope and Body nodes are in the http://schemas.xmlsoap.org/soap/envelope/ namespace while their child nodes are in the empty namespace, which is what is reflected in my sample code.

  3. XmlNode.AppendChild(XmlNode) returns the appended child and so can be used in a fluent style.

  4. In the sample XML the innermost elements are explicitly specified to have a default namespace of "":

    <AddressLine1 xmlns="">50 W TOWN ST</AddressLine1>

    Actually the xmlns="" is unnecessary because there is no default namespace specified at a higher level in the XML. Thus the following is semantically identical and sufficient:

    <AddressLine1>50 W TOWN ST</AddressLine1>

    If for some reason you are required to have this redundant namespace declaration, you can do:

    var line1 = body.AppendChild(doc.CreateElement("", "AddressLine1", bodyNs));
    line1.Attributes.Append(doc.CreateAttribute("xmlns")).Value = bodyNs;
    line1.InnerText = "50 W TOWN ST";

    Which results in

    <AddressLine1 xmlns="">50 W TOWN ST</AddressLine1>
  5. XmlElement.InnerText can be used to set the text value of a element with no child elements. This is more succinct than calling CreateTextNode() then appending the result to the DOM.

Working sample .Net fiddle here.

generate xml files based on my c# classes

Create following classes to hold your data and validate it:

public class Community
{
public string Author { get; set; }
public int CommunityId { get; set; }
public string Name { get; set; }
[XmlArray]
[XmlArrayItem(typeof(RegisteredAddress))]
[XmlArrayItem(typeof(TradingAddress))]
public List<Address> Addresses { get; set; }
}

public class Address
{
private string _postCode;

public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string City { get; set; }
public string Country { get; set; }

public string PostCode
{
get { return _postCode; }
set {
// validate post code e.g. with RegEx
_postCode = value;
}
}
}

public class RegisteredAddress : Address { }
public class TradingAddress : Address { }

And serialize that instance of community class to xml:

Community community = new Community {
Author = "xxx xxx",
CommunityId = 0,
Name = "name of community",
Addresses = new List<Address> {
new RegisteredAddress {
AddressLine1 = "xxx",
AddressLine2 = "xxx",
AddressLine3 = "xxx",
City = "xx",
Country = "xxxx",
PostCode = "0000-00"
},
new TradingAddress {
AddressLine1 = "zz",
AddressLine2 = "xxx"
}
}
};

XmlSerializer serializer = new XmlSerializer(typeof(Community));
serializer.Serialize(File.Create("file.xml"), community);

I think a little googling will help you to understand how to deserialize community object back from file.

How to generate an XML file with specific structure using C#?

Check the XElement class: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/creating-xml-trees-linq-to-xml-2

The basic example is this:

XElement contacts =  
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);

Using the ToString() function on the XElement object will return the value in string format.

To generate attributes like the id, you can use the XAttribute class like this:

XElement phone = new XElement("Phone",  
new XAttribute("Type", "Home"),
"555-555-5555");
Console.WriteLine(phone);

How to create xml from a template-c#

You can use XmlSerializer and create a simple class with properties according to the template:

public class User
{
public UserId{get;set;}

...
}

And serialize the class to XML file.

There's a good example here.

Option #2:

If for some reason you do not want to use XmlSerializer use XmlWriter - in order to prevent forgetting to close elements I suggest you use "AutoClose" XmlWriter - I've blogged about how to create this simple class on my blog - XmlWriter that automatically close elements using IDisposable

How to build XML Tree in c# with the available structure of XML Tree

Try following recursive algorithm using Xml Linq

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


namespace ConsoleApplication157
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
string[] inputs = {
"a/b.book",
"a/b/c.book",
"a/b/c/d/e.page",
"a/b/c/d/f.page",
"a/b/g.book",
"a/b/g/h/i.page",
"a/b/g/h/j.page",
"k/l.book",
"k/l/m/n.page",
"o/p.book"
};
List<List<string>> splitArrays = inputs.Select(x => x.Split(new char[] { '/', '.' }).ToList()).ToList();

XElement root = new XElement("root");
GetTree(root, splitArrays);

}
static void GetTree(XElement parent, List<List<string>> splitArrays)
{
var groups = splitArrays.OrderBy(x => x[0]).GroupBy(x => new { path = x.First(), type = x.Last() }).ToArray();
foreach (var group in groups)
{
List<List<string>> children = null;
XElement element = new XElement(group.Key.type, new XAttribute("navtitle", group.Key.path));
parent.Add(element);
Boolean first = true;
foreach (var child in group.OrderByDescending(x => x.Count))
{
if (child.Count() == 2) //since we sorts by count, 1 indicates we are at the leaf
{
if (first)
{
if (children != null)
{
GetTree(element, children);
children = null;
}
first = false;
}
}
else
{
//remove first index of each splitArray
if (children == null) children = new List<List<string>>();
List<string> newChild = child.Skip(1).ToList();
children.Add(newChild);
}

}
//when there are no elements with count = 1 then call Getree here
if (children != null)
{
GetTree(element, children);
}

}
}
}
}


Related Topics



Leave a reply



Submit