使用c# XDocument输出XML数据到CSV文本文件

本文关键字:CSV 文本 文件 数据 XML XDocument 输出 使用 | 更新日期: 2023-09-27 18:17:22

我正在使用Visual Studio 2015并使用Visual c#/XAML WPF项目。

我所拥有的是一个.xml文档,其中包含我想要读取、操作的值,并将结果输出到具有特定标题的逗号分隔的.csv文件。我相信我已经得到了大部分的代码正确,但似乎有嵌套元素的水平的问题。这段代码成功地创建了一个。csv文件,但是它总是空的。

我已经对代码的. descendants()和. elements()部分进行了实验,但无法将任何内容写入文件。我认为我可以通过使用XDocument类来实现我的目标,如果可能的话,我希望不使用任何其他资源。

任何帮助都是感激的!这是我第一次在这里发帖,所以如果需要任何额外的信息,我将很高兴补充更多。

c#代码:

private void testMethod()
    {
        StringBuilder sb = new StringBuilder();
        string delimiter = ",";
        XDocument.Load(@"C:'Users'Paulie'Desktop'Flight1.xml")
                   .Descendants("trk")
                   .Elements()
                   .ToList()
                   .ForEach(element => sb.Append(
            element.Attribute("lon").Value + delimiter +
            element.Attribute("lat").Value + delimiter +
            element.Element("ele").Value + delimiter +
            element.Element("time").Value + delimiter +
            element.Element("course").Value + delimiter +
            element.Element("pitch").Value + delimiter +
            element.Element("roll").Value +
            "'r'r"));
        StreamWriter sw = new StreamWriter(@"C:'Users'Paulie'Desktop'Flight1.csv");
        sw.WriteLine(sb.ToString());
        sw.Close();
        Console.WriteLine(sb.ToString());
    }

XML源样例(不友好的版本,正如它写在XML文本中一样):

<gpx creator="Mission Planner 1.3.29 build 1.1.5646.37690" xmlns="http://www.topografix.com/GPX/1/1"><trk><trkseg><trkpt lat="30.3020034" lon="-96.4781874"><ele>89.96</ele><time>2016-08-30T08:46:16-05:00</time><course>56.32</course><roll>-3.11</roll><pitch>-5.99</pitch><mode /></trkpt><trkpt lat="30.3020015" lon="-96.4781862"><ele>89.45</ele><time>2016-08-30T08:46:19-05:00</time><course>56.3</course><roll>-3.06</roll><pitch>-6.06</pitch><mode /></trkpt><trkpt lat="30.3020013" lon="-96.4781861"><ele>89.42</ele><time>2016-08-30T08:46:19-05:00</time><course>56.3</course><roll>-3.06</roll><pitch>-6.11</pitch><mode /></trkpt><trkpt lat="30.3020012" lon="-96.478186"><ele>89.38</ele><time>2016-08-30T08:46:19-05:00</time><course>56.29</course><roll>-3.05</roll><pitch>-6.14</pitch><mode /></trkpt><trkpt lat="30.302001" lon="-96.4781859"><ele>89.35</ele><time>2016-08-30T08:46:20-05:00</time><course>56.29</course><roll>-3.06</roll><pitch>-6.13</pitch><mode /></trkpt><trkpt lat="30.3020009" lon="-96.4781858"><ele>89.32</ele><time>2016-08-30T08:46:20-05:00</time><course>56.28</course><roll>-3.07</roll><pitch>-6.17</pitch><mode /></trkpt><trkpt lat="30.3020007" lon="-96.4781856"><ele>89.29</ele><time>2016-08-30T08:46:20-05:00</time><course>56.27</course><roll>-3.08</roll><pitch>-6.17</pitch><mode /></trkpt><trkpt lat="30.3020005" lon="-96.4781855"><ele>89.25</ele><time>2016-08-30T08:46:20-05:00</time><course>56.26</course><roll>-3.1</roll><pitch>-6.2</pitch><mode /></trkpt><trkpt lat="30.3020004" lon="-96.4781854"><ele>89.22</ele><time>2016-08-30T08:46:20-05:00</time><course>56.26</course><roll>-3.1</roll><pitch>-6.21</pitch><mode /></trkpt><trkpt lat="30.3020003" lon="-96.4781853"><ele>89.2</ele><time>2016-08-30T08:46:21-05:00</time><course>56.25</course><roll>-3.1</roll><pitch>-6.24</pitch><mode /></trkpt><trkpt lat="30.3020002" lon="-96.4781852"><ele>89.17</ele><time>2016-08-30T08:46:21-05:00</time><course>56.24</course><roll>-3.12</roll><pitch>-6.26</pitch><mode /></trkpt><trkpt lat="30.302" lon="-96.4781851"><ele>89.16</ele><time>2016-08-30T08:46:21-05:00</time><course>56.23</course><roll>-3.12</roll><pitch>-6.29</pitch><mode /></trkpt><trkpt lat="30.3019999" lon="-96.478185"><ele>89.13</ele><time>2016-08-30T08:46:21-05:00</time><course>56.23</course><roll>-3.12</roll><pitch>-6.32</pitch><mode /></trkpt><trkpt lat="30.3019998" lon="-96.4781848"><ele>89.09</ele><time>2016-08-30T08:46:22-05:00</time><course>56.2</course><roll>-3.09</roll><pitch>-6.36</pitch><mode /></trkpt><trkpt lat="30.3019997" lon="-96.4781847"><ele>89.08</ele><time>2016-08-30T08:46:22-05:00</time><course>56.2</course><roll>-3.09</roll><pitch>-6.38</pitch><mode /></trkpt><trkpt lat="30.3019996" lon="-96.4781846"><ele>89.06</ele><time>2016-08-30T08:46:22-05:00</time><course>56.21</course><roll>-3.1</roll><pitch>-6.28</pitch><mode /></trkpt><trkpt lat="30.3019995" lon="-96.4781845"><ele>89.04</ele><time>2016-08-30T08:46:22-05:00</time><course>56.2</course><roll>-3.1</roll><pitch>-6.22</pitch><mode /></trkpt></trkseg></trk></gpx>

期望输出示例:

TimeStamp,SensorLatitude,SensorLongitude,SensorAltitude,PlatformHeading,PlatformPitch,PlatformRoll
1472525176000000,30.3020034,-96.4781874,89.96,56.32,-5.99,-3.11
1472525179000000,30.3020015,-96.4781862,89.45,56.3,-6.06,-3.06
1472525179000000,30.3020013,-96.4781861,89.42,56.3,-6.11,-3.06
1472525179000000,30.3020012,-96.478186,89.38,56.29,-6.14,-3.05
1472525180000000,30.302001,-96.4781859,89.35,56.29,-6.13,-3.06
1472525180000000,30.3020009,-96.4781858,89.32,56.28,-6.17,-3.07

(注意,TimeStamp列包含整数值,而不是日期-时间格式。这是我需要使用另一个函数(将日期时间格式转换为Posix/Unix时间签名)更改的字段

使用c# XDocument输出XML数据到CSV文本文件

另一种方法:

string[] valuesToPrint = { "lon", "lat", "ele", "time", "course", "pitch", "roll" };
XNamespace ns = "http://www.topografix.com/GPX/1/1";
File.WriteAllLines("Flight1.csv",
    new[] { string.Join(",", valuesToPrint) }
    .Concat(XDocument.Load("Flight1.xml")
    .Descendants(ns + "trkpt")
    .Select(e =>
    {
        return string.Join(",", e.Attributes()
            .Where(a => valuesToPrint.Contains(a.Name.LocalName))
            .Select(a => a.Value)
            .Concat(e.Elements()
                .Where(c => valuesToPrint.Contains(c.Name.LocalName))
                .Select(c => c.Value)).ToArray());
    })));

使用测试XML的输出:

lon,lat,ele,time,course,pitch,roll
-96.4781874,30.3020034,89.96,2016-08-30T08:46:16-05:00,56.32,-3.11,-5.99
-96.4781862,30.3020015,89.45,2016-08-30T08:46:19-05:00,56.3,-3.06,-6.06
-96.478186,30.3020012,89.38,2016-08-30T08:46:19-05:00,56.29,-3.05,-6.14
-96.4781859,30.302001,89.35,2016-08-30T08:46:20-05:00,56.29,-3.06,-6.13
-96.4781858,30.3020009,89.32,2016-08-30T08:46:20-05:00,56.28,-3.07,-6.17

由于我不确定您希望输出的确切格式,因此这可能有点偏离目标!

分解如下:

  • 将以下集合中的每一行写入文件" flight .csv"
  • 集合中的第一个元素是用逗号连接的标题名称
  • 所有后续元素对应于XML
  • 中的每个trkpt条目
  • 对于每个trkp条目,选择名称包含在valuesToPrint中的所有属性和子元素的值,并用逗号将这些值连接起来。

Elements()获取所有子元素。当你这样做时:

.Descendants("trk").Elements()

您选择了所有trkseg元素(trk元素的子元素)。您的数据位于trkpt元素内部,因此您可能需要这样的内容:

XDocument.Load(@"C:'Users'Paulie'Desktop'Flight1.xml")
    .Descendants("trkpt")
    .ForEach(...);

另外,由于XML位于名称空间中,因此在查找节点时需要指定:

.Descendants("{http://www.topografix.com/GPX/1/1}trkpt")

在使用原始XML源代码一段时间后,我意识到在文件的开头和结尾有一堆完全不必要的额外数据,除了导致我的程序出现问题之外什么也没有。

我最终做的是切断XML代码的开始和结束部分(使用and作为开始和结束索引),以便我可以轻松地使用我的原始方法将XML结构转换为CSV结构。

现在一切正常!感谢每一个花时间帮助我的人。