XML数据到CSV转换

时间:2015-06-03 03:05:51

标签: c# xml parsing csv xml-parsing

所以我有一个设备,它有一个内置的记录程序,可以生成有关设备的状态消息,并不断将它们推送到.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#相当新,所以我不确定要走哪条路。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:2)

由于文件中的每个顶级XML节点格式正确,您可以使用XmlReaderXmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment来遍历文件中的每个顶级节点,并使用Linq-读取它到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>。如果真实文件中不存在该空间,则可以省略该子句。

答案 1 :(得分:1)

这是我使用XML Linq的解决方案。我通过使用Root标记包装片段来创建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();

        }
    }
}
​

答案 2 :(得分:1)

由于非标准格式必须从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();

        }
    }
}
​