Штепа Іван
Штепа Іван

Reputation: 23

How to convert XML to CSV (C#)

XML:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <Company>
    <Title>Seph</Title>
    <Commentary>blah-blah</Commentary>
    <Worker1>Bill</Worker1>
    <Worker2>Fill</Worker2>
  </Company>
  <JobDetails>
    <JobNum>1</JobNum>
    <Detail1>Sport</Detail1>
    <Detail2>Physical</Detail2>
  </JobDetails>
  <JobDetails>
    <JobNum>2</JobNum>
    <Detail1>Mailman</Detail1>
    <Detail2>pastoral</Detail2>
  </JobDetails>
  <JobDetails />
</NewDataSet>

I have an example of code converter (XML to CSV) but it works without headlines "Company" and "JobDetails". I need this headlines, can you help me to improve this code?

using System;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Linq;
namespace XML_CSV
{
    class Class1
    {
        static void Main()
        {
            StringBuilder sb = new StringBuilder();
            string delimiter = "|";

            XDocument.Load(@"C:\Users\Iuser\Desktop\Data.xml").Descendants("NewDataSet").ToList().ForEach(element => sb.Append(
                            element.Element("Company").Value + delimiter +  //something maybe bad here
                            element.Element("Title").Value + delimiter +
                            element.Element("Commentary").Value + delimiter +
                            element.Element("Worker1").Value + delimiter +
                            element.Element("Worker2").Value + delimiter +
                             element.Element("JobDetails").Value + delimiter + //something maybe bad here
                             element.Element("Detail1").Value + delimiter +
                             element.Element("Detail2").Value + "\r\n"));
            StreamWriter sw = new StreamWriter(@"C:\Users\Iuser\Desktop\DataCSV.csv");
            sw.WriteLine(sb.ToString());
            sw.Close();

        }
    }
}

Possibly code don't work because visual thinks that "Company" and "JobDetails" it's different Tables. This is should look like this (In CSV of cours): Company JobDetails

It should be in one CSV file.

Output text:

Title,Commentary,Worker1,Worker2
Seph,blah-blah,Bill,Fill
JobNum,Detail1,Detail2
1,Sport,Physical
2,Mailman,pastoral

Upvotes: 0

Views: 498

Answers (2)

Cinchoo
Cinchoo

Reputation: 6326

Well, using XSLT for the xml to csv transformation is one way to do it. Here is one another approach using Cinchoo ETL, an open source library to perform the transformation in native way

StringBuilder csv1 = new StringBuilder();
using (var r = new ChoXmlReader("XmlFile3.xml")
    .WithXPath("/Company")
    )
{
    using (var w = new ChoCSVWriter(csv1)
        .WithFirstLineHeader()
        .UseNestedKeyFormat(false)
        )
        w.Write(r);
}

StringBuilder csv2 = new StringBuilder();
using (var r = new ChoXmlReader("XmlFile3.xml")
    .WithXPath("/JobDetails")
    )
{
    using (var w = new ChoCSVWriter(csv2)
        .WithFirstLineHeader()
        .UseNestedKeyFormat(false)
        )
        w.Write(r);
}

string combinedCSV = csv1.ToString() + Environment.NewLine + csv2.ToString();

Console.WriteLine(combinedCSV);

Output:

Title,Commentary,Worker1,Worker2
Seph,blah-blah,Bill,Fill
JobNum,Detail1,Detail2
1,Sport,Physical
2,Mailman,pastoral

Upvotes: 1

Yitzhak Khabinsky
Yitzhak Khabinsky

Reputation: 22321

By using XSLT.

XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/NewDataSet">
        <xsl:text>Title,Commentary,Worker1,Worker2</xsl:text>
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates select="Company"/>
        <xsl:text>JobNum,Detail1,Detail2</xsl:text>
        <xsl:text>&#xA;</xsl:text>
        <xsl:for-each select="JobDetails[*]">
            <xsl:value-of select="concat(JobNum, ',', Detail1, ',', Detail2)"/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="Company">
        <xsl:value-of select="concat(Title, ',', Commentary, ',', Worker1, ',', Worker2)"/>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

c#

void Main()
{
    const string SOURCEXMLFILE = @"e:\Temp\XML_to_CSV\input.xml";
    const string XSLTFILE = @"e:\Temp\XML_to_CSV\process.xslt";
    const string OUTPUTFILE = @"e:\Temp\XML_to_CSV\output.csv";

    try
    {
        XsltArgumentList xslArg = new XsltArgumentList();

        using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
        {
            XslCompiledTransform xslt = new XslCompiledTransform();
            xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());

            XmlWriterSettings settings = xslt.OutputSettings.Clone();
            settings.IndentChars = "\t";
            // to remove BOM
            settings.Encoding = new UTF8Encoding(false);

            using (XmlWriter result = XmlWriter.Create(OUTPUTFILE, settings))
            {
                xslt.Transform(src, xslArg, result, new XmlUrlResolver());
                result.Close();
            }
        }
        Console.WriteLine("File '{0}' has been generated.", OUTPUTFILE);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

Output

Title,Commentary,Worker1,Worker2
Seph,blah-blah,Bill,Fill
JobNum,Detail1,Detail2
1,Sport,Physical
2,Mailman,pastoral

Upvotes: 2

Related Questions