类似XML的数据到CSV的转换
本文关键字:CSV 转换 数据 XML 类似 | 更新日期: 2023-09-27 17:53:11
所以我有一个设备,它有一个内置的记录器程序,它生成关于设备的状态消息,并不断将它们推送到.txt
文件。这些消息包括有关设备状态、网络状态以及许多其他事情的信息。文件中的数据如下所示:
<XML><DSTATUS>1,4,7,,5</DSTATUS><EVENT> hello,there,my,name,is,jack,</EVENT>
last,name,missing,above <ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG> </XML>
<XML><DSTATUS>1,5,7,,3</DSTATUS><EVENT>hello,there,my,name,is,mary,jane</EVENT>
last,name,not,missing,above<ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG></XML>
... goes on
注意,它不是格式良好的XML。此外,一个元素可以有多个参数,也可以有空格……例如:<NETWORKSTAT>1,456,3,6,,7</NETWORKSTAT>
我的目标是在c# WPF中编写一些东西,这将采用此文本文件,处理其中的数据并创建每行每个事件的.csv
文件。例如,对于上面给出的简短示例,csv文件中的第一行将是:
1,4,7,,5,hello,there,my,name,is,jack,,last,name,missing,above,3,6,7,,8,4
同样,我不需要使用基本c#的帮助。我知道如何读取文件等等。但我没有线索,我将如何处理这个问题,关于解析和处理和转换。我对c#相当陌生,所以我不确定该往哪个方向走。任何帮助将不胜感激!
由于文件中的每个顶级XML节点都是格式良好的,因此可以使用XmlReader
和XmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment
来遍历文件中的每个顶级节点,并使用Linq-to-XML读取它:
public static IEnumerable<string> XmlFragmentsToCSV(string path)
{
using (var textReader = new StreamReader(path, Encoding.UTF8))
foreach (var line in XmlFragmentsToCSV(textReader))
yield return line;
}
public static IEnumerable<string> XmlFragmentsToCSV(TextReader textReader)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(textReader, settings))
{
while (reader.Read())
{ // Skip whitespace
if (reader.NodeType == XmlNodeType.Element)
{
using (var subReader = reader.ReadSubtree())
{
var element = XElement.Load(subReader);
yield return string.Join(",", element.DescendantNodes().OfType<XText>().Select(n => n.Value.Trim()).Where(t => !string.IsNullOrEmpty(t)).ToArray());
}
}
}
}
}
为了精确匹配您想要的输出,我必须在每个文本节点值的开始和结束处修剪空白。
此外,Where(t => !string.IsNullOrEmpty(t))
子句将跳过与此处空格对应的空白节点:</ANOTHERTAG> </XML>
。如果实际文件中不存在该空格,则可以省略该子句。
由于非标准格式不得不从XML Linq解决方案切换到标准XML解决方案。Linq不支持不在标签中的TEXT字符串。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:'temp'test.csv";
static void Main(string[] args)
{
string input =
"<XML><DSTATUS>1,4,7,,5</DSTATUS><EVENT> hello,there,my,name,is,jack,</EVENT>" +
"last,name,missing,above <ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG> </XML>" +
"<XML><DSTATUS>1,5,7,,3</DSTATUS><EVENT>hello,there,my,name,is,mary,jane</EVENT>" +
"last,name,not,missing,above<ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG></XML>";
input = "<Root>" + input + "</Root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(input);
StreamWriter writer = new StreamWriter(FILENAME);
XmlNodeList rows = doc.GetElementsByTagName("XML");
foreach (XmlNode row in rows)
{
List<string> children = new List<string>();
foreach (XmlNode child in row.ChildNodes)
{
children.Add(child.InnerText.Trim());
}
writer.WriteLine(string.Join(",", children.ToArray()));
}
writer.Flush();
writer.Close();
}
}
}
这是我使用XML Linq的解决方案。我通过用根标记包装这些片段来创建XDocument。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:'temp'test.csv";
static void Main(string[] args)
{
string input =
"<XML><DSTATUS>1,4,7,,5</DSTATUS><EVENT> hello,there,my,name,is,jack,</EVENT>" +
"last,name,missing,above <ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG> </XML>" +
"<XML><DSTATUS>1,5,7,,3</DSTATUS><EVENT>hello,there,my,name,is,mary,jane</EVENT>" +
"last,name,not,missing,above<ANOTHERTAG>3,6,7,,8,4</ANOTHERTAG></XML>";
input = "<Root>" + input + "</Root>";
XDocument doc = XDocument.Parse(input);
StreamWriter writer = new StreamWriter(FILENAME);
List<XElement> rows = doc.Descendants("XML").ToList();
foreach (XElement row in rows)
{
string[] elements = row.Elements().Select(x => x.Value).ToArray();
writer.WriteLine(string.Join(",", elements));
}
writer.Flush();
writer.Close();
}
}
}