2016-11-10 64 views
-2

我正在使用Visual Studio 2015並使用Visual C#/ XAML WPF項目。使用C#將XML數據輸出到CSV文本文件XDocument

我所擁有的是一個.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時間簽名的函數進行更改)

+0

這將是巨大的,也看到期望的CSV是在輸出格式的例子。 – TVOHM

+0

感謝您的建議,我添加所需的輸出的一小部分。 –

回答

0

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") 
+0

謝謝,這有助於澄清我應該傳遞給.Descendants()的參數。不幸的是,將其設置爲「trkpt」仍會創建一個空白文件。也許我應該分離出一些代碼,而不是試圖將整個函數捆綁到一行中。 –

+0

我不知道'ForEach'是從哪裏來的,但我猜它正在返回一個冷IEnumerable',所以你的代碼實際上並沒有被執行。 –

+0

此外,您的XML正在使用命名空間,這就解釋了爲什麼通過XLinq沒有發現任何東西。包含該更新的答案。 –

0

另一種方法:使用您的測試XML

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()); 
    }))); 

輸出:

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 

由於我不確定您希望輸出的確切格式,所以這可能會有些偏離標準!

這種分解如下:

  • 編寫以下收集到的文件「Flight1中的每一行。CSV」
  • 集合中的第一個元素是由逗號
  • 所有後續元素對應於XML
  • 每trkp後的每trkpt條目加入了頭名,選擇所有屬性和子元素的值他的名字被包含在valuesToPrint,並用逗號加入這些值。
+0

這太棒了,非常感謝!我這次獲取CSV文件中的標題行,但由於某些原因,沒有任何字段正在寫入。我會繼續調整它。 –

+0

我猜測,實際的源XML(我在原始文章中更新的)實際上與您的函數使用的XML稍有不同。也許這就是爲什麼我沒有得到任何東西寫入文件。你有什麼建議可以調整我的原始方法嗎? –

+0

到目前爲止,這是我可以生成任何輸出以寫入.CSV文件的唯一方法。是否有道理,我必須以某種方式指定命名空間以將實際數據寫入文件中? –

0

用了一段時間的原始XML源的工作後,我意識到,有文件的開頭一堆額外的數據,並結束該是完全沒有必要的,除了導致我的程序出現問題之外,沒有其他更多的事情。

我最終做的是切斷XML代碼的開始和結束部分(使用和作爲開始和結束索引),以便我可以輕鬆使用我原來的將XML結構轉換爲CSV結構的方法。

所有正在工作!感謝所有花時間幫助我的人。