Click here to Skip to main content
15,887,083 members
Please Sign up or sign in to vote.
2.33/5 (3 votes)
See more:
I have the code below trying to convert a xml file to a csv file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FOLDER = @"c:\temp\";
        const string CSV_FILENAME = @"c:\temp\test.csv";

        static void Main(string[] args)
        {
            string[] xmlFiles = Directory.GetFiles(FOLDER, "*.xml");
            StreamWriter writer = new StreamWriter(CSV_FILENAME);
            Boolean firstLine = true;
            for (int idx = 0; idx < xmlFiles.Length; idx++)
            {
                string file_name = xmlFiles[idx];
                XDocument doc = XDocument.Load(file_name);

                foreach (XElement data in doc.Descendants("VehicleBreadcrumb"))
                {
                    if (firstLine)
                    {
                        string[] headers = data.Elements().Select(x => x.Name.LocalName).ToArray();
                        writer.WriteLine(string.Join(",", headers));
                        firstLine = false;
                    }
                    string[] row = data.Elements().Select(x => (string)x).ToArray();
                    writer.WriteLine(string.Join(",", row));
                }
            }
            writer.Flush();
            writer.Close();
        }
    }

}


What I have tried:

Can find an answer on the web. Sample of my xml file
XML
<ArrayOfVehicleBreadcrumb xmlns="http://schemas.datacontract.org/2004/07/Xata.Ignition.WebServiceAPI.Contracts.DataContract.StatusAndEvents" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><VehicleBreadcrumb><BreadcrumbIdentity>595197889-0</BreadcrumbIdentity><Direction>North</Direction><DriverID>0932</DriverID><DriverName>xxxxx xxxx</DriverName><DriverSID>5408</DriverSID><EngineHours>9575.35</EngineHours><EngineSpeed>800.125</EngineSpeed><GPSDateTime>2023-08-09T07:01:00</GPSDateTime><GPSSpeed>0</GPSSpeed><Heading>360</Heading><IgnitionStatus>ON</IgnitionStatus><Latitude>38.548811</Latitude><Location>1.7 mi North North West of Township of Mascoutah, Illinois</Location><Longitude>-89.771953</Longitude><ModifiedDateTime>2023-08-09T07:05:55.57721</ModifiedDateTime><Motion>Stopped</Motion><Odometer>336485.80000000005</Odometer><OrganizationID>301165</OrganizationID><OrganizationName>xx Inc.</OrganizationName><OrganizationSID>64</OrganizationSID><RoadSpeed>0</RoadSpeed><VehicleName>349204</VehicleName><VehicleSID>1772</VehicleSID></VehicleBreadcrumb><VehicleBreadcrumb><BreadcrumbIdentity>595197891-0</BreadcrumbIdentity><Direction>North</Direction><DriverID>0932</DriverID><DriverName>xxxxx xxxxx</DriverName><DriverSID>5408</DriverSID><EngineHours>9575.4</EngineHours><EngineSpeed>800.625</EngineSpeed><GPSDateTime>2023-08-09T07:05:00</GPSDateTime><GPSSpeed>0</GPSSpeed><Heading>360</Heading><IgnitionStatus>ON</IgnitionStatus><Latitude>38.548811</Latitude><Location>1.7 mi North North West of Township of Mascoutah, Illinois</Location><Longitude>-89.771953</Longitude><ModifiedDateTime>2023-08-09T07:05:55.57721</ModifiedDateTime><Motion>Stopped</Motion><Odometer>336485.80000000005</Odometer><OrganizationID>301165</OrganizationID><OrganizationName>Txxx Inc.</OrganizationName><OrganizationSID>64</OrganizationSID><RoadSpeed>0</RoadSpeed><VehicleName>349204</VehicleName><VehicleSID>1772</VehicleSID></VehicleBreadcrumb>
Posted
Updated 9-Aug-23 22:26pm
v3
Comments
PIEBALDconsult 9-Aug-23 12:25pm    
What foreach loop? I don't think that will even compile, you must have mis-pasted the code.

OK, that looks better. I think the issue is that there is a default namespace [ xmlns="http://schemas.datacontract.org/2004/07/Xata.Ignition.WebServiceAPI.Contracts.DataContract.StatusAndEvents" ] which you need to resolve.

P.S. I have been trying to see how to do that, but I don't use XDocument, so I don't know how. I use XmlDocument so I can probably give an example using that.
You'll need to add the namespace to the namespace manager and specify it in [ doc.Descendants("VehicleBreadcrumb") ]
Member 15627495 9-Aug-23 13:40pm    
an XElement could be a big big wide Xml String...

you have to debug your code, are you sure all the values you need are pick by your linq query ?

define few lines to display the values contents in the log part

The XML has a default namespace, so you have to include it in the name of the objects to retrieve.

Try
foreach (XElement data in doc.Descendants(doc.Root.GetDefaultNamespace() + "VehicleBreadcrumb"))
 
Share this answer
 
v4
Comments
Richard Deeming 10-Aug-23 4:28am    
The correct solution! :)
The problem is with your XML data:
XML
<ArrayOfVehicleBreadcrumb 
    xmlns="http://schemas.datacontract.org/2004/07/Xata.Ignition.WebServiceAPI.Contracts.DataContract.StatusAndEvents" 
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

It seems that the site URL to schemas.datacontract.org is not accessible. So by removing the first xmlns entry, the code produces the correct results. So change the first entry of the XML file to:
XML
<ArrayOfVehicleBreadcrumb
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">


[edit]
Andre Oosthuizen's Solution explains why this happens, and how to resolve it.
[/edit]
 
Share this answer
 
v4
Comments
Andre Oosthuizen 11-Aug-23 5:20am    
You were 100% correct, seems the pond life affected you as well, my counter 5
Richard MacCutchan 11-Aug-23 5:25am    
Thanks. I usually ignore such things, but it appears that they flagged everyone except PIEBALDconsult.
If your XML has a default namespace, you need to account for it in your code when querying the elements. You should use the 'XNamespace' and 'XName' objects to handle your namespaces -
C#
XNamespace ns = "http://schemas.datacontract.org/2004/07/Xata.Ignition.WebServiceAPI.Contracts.DataContract.StatusAndEvents";
foreach (XElement data in doc.Descendants(ns + "VehicleBreadcrumb"))
{
    if (firstLine)
    {
        string[] headers = data.Elements().Select(x => x.Name.LocalName).ToArray();
        writer.WriteLine(string.Join(",", headers));
        firstLine = false;
    }
    string[] row = data.Elements().Select(x => (string)x).ToArray();
    writer.WriteLine(string.Join(",", row));
}
 
Share this answer
 
v3
Comments
Richard MacCutchan 10-Aug-23 5:06am    
+5, an actual solution rather than my guesswork.
Andre Oosthuizen 10-Aug-23 5:37am    
Lol, thank you!
Richard MacCutchan 10-Aug-23 10:39am    
Looks like some pond life here does not like some of our suggestions.
PIEBALDconsult 10-Aug-23 11:04am    
Hard-coding the namespace is unnecessary and not a good idea.
Andre Oosthuizen 11-Aug-23 5:18am    
@Richard, so it seems.

@PIEBALD, you are right, could have been done better, your solution is the actual method to use, my +5.
Quote:
Code will not drop into the foreach loop.

Your code do not behave the way you expect, or you don't understand why !

There is an almost universal solution: Run your code on debugger step by step, inspect variables.
The debugger is here to show you what your code is doing and your task is to compare with what it should do.
There is no magic in the debugger, it don't know what your code is supposed to do, it don't find bugs, it just help you to by showing you what is going on. When the code don't do what is expected, you are close to a bug.
To see what your code is doing: Just set a breakpoint and see your code performing, the debugger allow you to execute lines 1 by 1 and to inspect variables as it execute
You should find pretty quickly what is wrong.

Debugger - Wikipedia, the free encyclopedia[^]

Mastering Debugging in Visual Studio 2010 - A Beginner's Guide[^]
Basic Debugging with Visual Studio 2010 - YouTube[^]

Debugging C# Code in Visual Studio - YouTube[^]

The debugger is here to only show you what your code is doing and your task is to compare with what it should do.
 
Share this answer
 
You only show one foreach loop, so it's got to be one of these lines:
C#
for (int idx = 0; idx < xmlFiles.Length; idx++)

C#
XDocument doc = XDocument.Load(file_name);

C#
foreach (XElement data in doc.Descendants("VehicleBreadcrumb"))

In all cases start with the debugger:
In the first case, check the value of xmlFiles.LengthIf it's zero, then ...
In the second case, check that the XML Load is returning in a timely fashion: if the file is too big, then it will take considerable time to load and it may be they you just aren't waiting long enough.
In the third case, check there are any Descendants with the right key. If there aren't any being found, then ...

We can't do any of that for you - we don't have access to your data or your code while it is running, and you need them both to start diagnosing the problem.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900