Solved

C#: Building XML file

Posted on 2015-01-06
13
462 Views
Last Modified: 2015-01-06
I am new to XML. A client requested to have our web application (C#) to generate an XML file. They gave us a sample XML file to use as a template (attached). We also have a stored procedure that returns the data needed to populate SOME of the fields in the XML file. sample.xml

I looked through some of the existing XML projects in our application (below) to hopefully get me started, but no luck.
XmlDeclaration xmldecl;
xmldecl = doc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmldecl, root);
...
...
...

What is the best way to generate the attached XML file using C#?

Can I do the following?
string xmlString = @"
<?xml version="1.0" encoding="UTF-8"?>
	<collectpay-payment-request xmlns="http://www.domain.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.domain.com ">
		<payment-batch-request>"

Open in new window

0
Comment
Question by:pzozulka
  • 7
  • 5
13 Comments
 
LVL 29

Accepted Solution

by:
anarki_jimbel earned 500 total points
ID: 40534311
No, never build an xml as a string. This is quite bad practice, and sometimes dangerous.

Try the following code.

You'll see - it's pretty easy to build xml using xml document.
 - you create a document,
- the you create a "root" element (you may have ONE only)
- then you create other elements and attach them to the root or to each other (depends on hierarchy).
- save (or print or send etc.)

 
using System.Xml;

...
       private void button1_Click(object sender, EventArgs e)
        {
            XmlDocument doc = new XmlDocument();

            // document element
            XmlElement cppr = doc.CreateElement("collectpay-payment-request");
            doc.AppendChild(cppr);

            // xml declaration
            XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
            XmlElement root = doc.DocumentElement;
            doc.InsertBefore(xmlDeclaration, root);

            // namespace
            root.SetAttribute("xmlns", "http://www.domain.com");
            root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
            root.SetAttribute("xsi", "http://www.domain.com");



            XmlElement pbr = doc.CreateElement("payment-batch-request");
            cppr.AppendChild(pbr);
            XmlElement bid = doc.CreateElement("business-id");
            //set element text to something you probably get from database, e.g., 1234
            bid.InnerText = "1234";
            pbr.AppendChild(bid);
            XmlElement prs = doc.CreateElement("payment-requests");
            pbr.AppendChild(prs);
            XmlElement bpr = doc.CreateElement("bank-payment-request");
            prs.AppendChild(bpr);
            XmlElement dbid = doc.CreateElement("division-business-id");
            //set element value to something you probably get from database, e.g., A777
            dbid.InnerText = "A777";
            bpr.AppendChild(dbid);          
            // Add bank account stuff to create the following structure:
            //<bank-account>
            //   <bank-account-type></bank-account-type>
            //   <routing-number></routing-number>
            //   <bank-account-number></bank-account-number>
            //   <account-holder-name></account-holder-name>
            //   <account-address-1 />
            //   <account-city />
            //   <account-state />
            //   <account-postal-code />
            //   <account-country-code></account-country-code>
            //</bank-account>
            XmlElement ba = doc.CreateElement("bank-account");
            bpr.AppendChild(ba);
            XmlElement bat = doc.CreateElement("bank-account-type");
            bat.InnerText = "cheque"; // from DB
            ba.AppendChild(bat);
            XmlElement rn = doc.CreateElement("routing-number");
            rn.InnerText = "333"; // from DB
            ba.AppendChild(rn);
            XmlElement ban = doc.CreateElement("bank-account-number");
            ban.InnerText = "012-987654321-00"; // from DB
            ba.AppendChild(ban);
            XmlElement ahn = doc.CreateElement("account-holder-name");
            ahn.InnerText = "John Doe"; // from DB
            ba.AppendChild(ahn);
            XmlElement aa1 = doc.CreateElement("account-address-1");
            aa1.InnerText = "1 Nowhere Street"; // from DB
            ba.AppendChild(aa1);
            XmlElement ac = doc.CreateElement("account-city");
            ac.InnerText = "New York"; // from DB
            ba.AppendChild(ac);
            XmlElement ast = doc.CreateElement("account-state");
            ast.InnerText = "New York"; // from DB
            ba.AppendChild(ast);
            XmlElement apc = doc.CreateElement("account-postal-code");
            apc.InnerText = "2222"; // from DB
            ba.AppendChild(apc);
            XmlElement acc = doc.CreateElement("account-country-code");
            acc.InnerText = "+1"; // from DB
            ba.AppendChild(acc); 

            // now nex element one level up:
            XmlElement nsec = doc.CreateElement("nacha-standard-entry-class");
            nsec.InnerText = @"Don't know what's that"; // from DB
            bpr.AppendChild(nsec); 

            // etc. - keep adding elements
                   

            doc.Save(@"C:\work\mytestxml.xml");

        }

Open in new window



Output:

<?xml version="1.0" encoding="UTF-8"?>
<collectpay-payment-request xmlns="http://www.domain.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi="http://www.domain.com">
  <payment-batch-request>
    <business-id>1234</business-id>
    <payment-requests>
      <bank-payment-request>
        <division-business-id>A777</division-business-id>
        <bank-account>
          <bank-account-type>cheque</bank-account-type>
          <routing-number>333</routing-number>
          <bank-account-number>012-987654321-00</bank-account-number>
          <account-holder-name>John Doe</account-holder-name>
          <account-address-1>1 Nowhere Street</account-address-1>
          <account-city>New York</account-city>
          <account-state>New York</account-state>
          <account-postal-code>2222</account-postal-code>
          <account-country-code>+1</account-country-code>
        </bank-account>
        <nacha-standard-entry-class>Don't know what's that</nacha-standard-entry-class>
      </bank-payment-request>
    </payment-requests>
  </payment-batch-request>
</collectpay-payment-request>

Open in new window

0
 
LVL 8

Author Comment

by:pzozulka
ID: 40534458
This all looks great except one thing. On line 20 in your code above, I am getting the following XmlException:

The ':' character, hexadecimal value 0x3A, cannot be included in a name.
0
 
LVL 33

Expert Comment

by:it_saige
ID: 40534519
And yet another method, simply serialize a class that represents your object returned from the database, i.e. (sample to get you going) -
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace EE_Q28591576
{
	class Program
	{
		static void Main(string[] args)
		{
			PaymentRequest pRequest = new PaymentRequest();
			pRequest.BankRequests.Add(new BankPaymentRequest() { BusinessID = "division business id" });
			pRequest.CreditCardRequests.Add(new CreditCardPaymentRequest() { BusinessID = "division business id" });
			PaymentBatchRequest pbRequest = new PaymentBatchRequest() { BusinessID = "business id" };
			pbRequest.Requests.Add(pRequest);
			CollectPayPaymentRequest request = new CollectPayPaymentRequest();
			request.Batch.Add(pbRequest);
			request.GenerateXml("text.xml");
		}
	}

	[Serializable(), XmlRoot("collectpay-payment-request", Namespace = BASE_NAMESPACE)]
	public class CollectPayPaymentRequest
	{
		private const string BASE_NAMESPACE = "http://www.domain.com";
		private const string XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";

		private readonly XmlSerializerNamespaces fNamespaces = new XmlSerializerNamespaces(new[] { new XmlQualifiedName(string.Empty, BASE_NAMESPACE), new XmlQualifiedName("xsi", XSI_NAMESPACE) });
		private readonly string fSchemaLocation = BASE_NAMESPACE;
		private readonly List<PaymentBatchRequest> fBatch = new List<PaymentBatchRequest>();

		[XmlNamespaceDeclarations]
		public XmlSerializerNamespaces Namespaces { get { return fNamespaces; } }

		[XmlAttribute(AttributeName = "schemaLocation", Namespace = XSI_NAMESPACE)]
		public string SchemaLocation { get { return fSchemaLocation; } }

		[XmlElement("payment-batch-request")]
		public List<PaymentBatchRequest> Batch { get { return fBatch; } }

		public void GenerateXml(string fileName)
		{
			GenerateXml(new FileInfo(fileName));
		}

		public void GenerateXml(FileInfo file)
		{
			XmlSerializer serializer = new XmlSerializer(typeof(CollectPayPaymentRequest));
			using (TextWriter writer = new StreamWriter(file.FullName))
				serializer.Serialize(writer, this);
		}
	}

	[Serializable()]
	public class PaymentBatchRequest
	{
		private readonly List<PaymentRequest> fRequests = new List<PaymentRequest>();

		[XmlElement("business-id")]
		public string BusinessID { get; set; }

		[XmlElement("payment-requests")]
		public List<PaymentRequest> Requests { get { return fRequests; } }
	}

	[Serializable()]
	public class PaymentRequest
	{
		private readonly List<BankPaymentRequest> fBankRequests = new List<BankPaymentRequest>();
		private readonly List<CreditCardPaymentRequest> fCreditCardRequests = new List<CreditCardPaymentRequest>();

		[XmlElement("bank-payment-requests")]
		public List<BankPaymentRequest> BankRequests { get { return fBankRequests; } }

		[XmlElement("credit-card-payment-requests")]
		public List<CreditCardPaymentRequest> CreditCardRequests { get { return fCreditCardRequests; } }
	}

	[Serializable()]
	public class BankPaymentRequest
	{
		[XmlElement("division-business-id")]
		public string BusinessID { get; set; }
	}

	[Serializable()]
	public class CreditCardPaymentRequest
	{
		[XmlElement("division-business-id")]
		public string BusinessID { get; set; }
	}
}

Open in new window

Produces the following output -Capture.JPGXml contains -Capture.JPG-saige-
0
 
LVL 8

Author Comment

by:pzozulka
ID: 40534581
it_saige:

Thanks, but I am already deep into a blend of anarki_jimbel's recommendation, and another way I found called XML to LINQ. However, I'm still stuck on the XmlException above.

I'm trying various ways, but still no luck, hoping someone can help:

Here's what I got:

XNamespace collectpay = "http://www.domain.com";
XNamespace xmlSchema = "http://www.w3.org/2001/XMLSchema-instance";

XDocument doc = new XDocument(
	new XElement("collectpay-payment-request",
			new XAttribute("xmlns", collectpay),
			new XAttribute(XNamespace.Xmlns + "xsi", xmlSchema),
			new XAttribute(XNamespace.Xmlns + "schemaLocation", collectpay),
		new XElement("payment-batch-request",
			new XElement("business-id", BUSINESS_ID.ToString()),

Open in new window


I am no longer getting the error above, but now getting a new error message:
The prefix '' cannot be redefined from '' to 'http://www.domain.com' within the same start element tag.
0
 
LVL 8

Author Comment

by:pzozulka
ID: 40534585
Am I not creating the XAttributes correctly?
0
 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 40534600
OK, you want use LINQ...

Need to check. Because this should not happen for XmlDocument. This is common approach.
Need some time :).
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 40534707
Try this:

            XNamespace blank = @"http://www.domain.com";
            XNamespace xsi = @"http://www.w3.org/2001/XMLSchema-instance";
            XNamespace schemaLocation = @"http://www.domain.com";

            XDocument doc = new XDocument(
	            new XElement(blank + "collectpay-payment-request",
			        new XAttribute("xmlns", blank),
                    new XAttribute(XNamespace.Xmlns + "xsi", xsi),
                    new XAttribute(xsi + "schemaLocation", schemaLocation),
		            new XElement(blank + "payment-batch-request",
			            new XElement("business-id", "business ID"),
                        new XElement("payment-requests",
                            new XElement("bank-payment-request",
                                new XElement("divizion-business-id", "A777"),
                                new XElement("bank-account",
                                    new XElement("bank-account-type", "cheque")
                                )
                            )
                        )
                    )
                )
            );


            doc.Save(@"C:\work\x_xml.xml");

Open in new window

0
 
LVL 29

Assisted Solution

by:anarki_jimbel
anarki_jimbel earned 500 total points
ID: 40534722
OK, try this, You may need to add "blank" namespace to each  element. Pretty confusing...

            XNamespace blank = @"http://www.domain.com";
            XNamespace xsi = @"http://www.w3.org/2001/XMLSchema-instance";
            XNamespace schemaLocation = @"http://www.domain.com";

            XDocument doc = new XDocument(
	            new XElement(blank + "collectpay-payment-request",
			        new XAttribute("xmlns", blank),
                    new XAttribute(XNamespace.Xmlns + "xsi", xsi),
                    new XAttribute(xsi + "schemaLocation", schemaLocation),
		            new XElement(blank + "payment-batch-request",
                        new XElement(blank + "business-id", "business ID"),
                        new XElement(blank + "payment-requests",
                            new XElement(blank + "bank-payment-request",
                                new XElement(blank + "divizion-business-id", "A777"),
                                new XElement(blank + "bank-account",
                                    new XElement(blank + "bank-account-type", "cheque")
                                )
                            )
                        )
                    )
                )
            );


            doc.Save(@"C:\work\x_xml.xml");

Open in new window

0
 
LVL 8

Author Comment

by:pzozulka
ID: 40534738
Messy...it works, but feels messy. I'll try to implement and see if this gets past the QA dept.

:) Hopefully there's a better solution to eliminate the blank...
0
 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 40534747
QA department looks at code?! :)

Adding a namespace to nested XElements is not MY solution :).
0
 
LVL 29

Assisted Solution

by:anarki_jimbel
anarki_jimbel earned 500 total points
ID: 40534751
OK, have a look at MSDN article below.
Hopefully your QA will be satisfied :D

http://msdn.microsoft.com/en-nz/library/bb387075.aspx



// Create an XML tree in a namespace.
XNamespace aw = "http://www.adventure-works.com";
XElement root = new XElement(aw + "Root",
    new XElement(aw + "Child", "child content")
);

0
 
LVL 8

Author Comment

by:pzozulka
ID: 40534760
Yea, since I'm the new Dev, QA management still does code review on me. :)

Wow, what a price to pay for adding attributes to a single line of XML code. I have nearly 60 child nodes.

Either way, thanks for your help.
0
 
LVL 29

Expert Comment

by:anarki_jimbel
ID: 40534793
Really, you have chosen the right approach.
With XmlDocument (my initial example - I'm a bit more comfortable with XmlDocument :))  -
you would have much more work :).
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Vb.net dynamic formulas in runtime 11 61
VB.Net How to Exit Sub - Exit Form??? 5 51
How would you add MULTITHREADING to the attached C# code? 4 51
Error in JQuery 5 38
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: http://www.codetwo.com/backup-for-office-365/ (http://www.codetwo.com/ba…
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now