类似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的数据到CSV的转换

由于文件中的每个顶级XML节点都是格式良好的,因此可以使用XmlReaderXmlReaderSettings.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();
        }
    }
}
​