Преобразование файла XML-сообщения в CSV

#c# #xml #csv

#c# #xml #csv

Вопрос:

Я получаю следующее XML-сообщение от банкомата, обрабатывающего депозиты. Теперь он должен быть преобразован в CSV и сохранен. Поскольку это не просто структурированный XML, у меня есть некоторые проблемы с ним. Я не могу отображать данные по отдельности в формате CSV.

 <?xml version="1.0" encoding="UTF-8"?>
<RemoteMessage operation="Device OK" DeviceID="SDM100-02378" CustomerCode="12345" Date="2020-09-06" Time="14:30:10" NOP="3013">
<content>
<count machineId="4" den="0.05" curr="CHF" qty="9" type="C" N="0" sType="B"/>
</content>
<devStatus>
<dev name="BDM" machineId="3" mod="SDM 100S" err="KO" devS="2"/>
<dev name="CDM" machineId="4" mod="CDS 508 (BV DE0)" err="OK" clean="0" door="0" devS="1" bag="2" cov="0" blk="00000000" ext="0"/>
</devStatus>
</RemoteMessage>
 

Вот что я пробовал:

 txtXML.Text = File.ReadAllText(comboBoxPath.Text);

var input = txtXML.Text;

// 1) Replace closing and opening tags with commas.
//    Include quotes in case any values have commas in them.
var result = Regex.Replace(input, @"(S)</[^>]*>s*<[^>]*>(S)", "$1","$2");

// 2) Put in CSV line breaks and remove xml delimiters, include leading and trailing quotes
result = Regex.Replace(result, @"</[^>]*>s*</RemoteMessage>s*<RemoteMessage>s*<[^>]*>", "rn");

// 3) Remove remaining tags and trim any whitespace
result = Regex.Replace(result, @"s*<.*>s*", "");

// 4) put in header row and first and last quotes            
result = DateTime.Now.ToString("yyyy.MM.dd")   ", "   DateTime.Now.ToString("HH:mm:ss")   ", "   "d, "   "content"   result   "";

txtCSV.Text = resu<
 

Я тоже пробовал это:

 using (CsvWriter writer = new CsvWriter(@"C:UsersAdminDesktopCSVMessage.csv"))
using (XmlRecordReader reader = new XmlRecordReader(@"C:UsersAdminDesktopXMLMessage.xml", "RemoteMessage/RemoteMessage"))
{
     reader.Columns.Add("content", "content");
     //reader.Columns.Add("devStatus", "devStatus");                

     writer.Write("machineId");
     //writer.Write("name");

     writer.EndRecord();

     while (reader.ReadRecord())
     {
        writer.Write(reader["machineId"]);
        //writer.Write(reader["name"]);
        
        writer.EndRecord();
     }
     reader.Close();
     writer.Close();
}
 

В обоих примерах указаны только заголовки, но нет значений. Кто-нибудь может помочь?

Ответ №1:

Попробуйте выполнить следующее :

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication176
{
    class Program
    {
        const string INPUT_FILENAME = @"c:temptest.xml";
        const string OUTPUT_FILENAME = @"c:temptest.csv";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(INPUT_FILENAME);
            StringReader sReader = new StringReader(xml);
            XmlReader xReader = XmlReader.Create(sReader);
            XmlSerializer serializer = new XmlSerializer(typeof(RemoteMessage));
            RemoteMessage remoteMessage = (RemoteMessage)serializer.Deserialize(xReader);

            string[] headers = new string[] {
                "operation",
                "DeviceID",
                "CustomerCode",
                "Date",
                "NOP",
                "machineId",
                "den",
                "curr",
                "qty",
                "type",
                "N",
                "sType",
                "name",
                "machineID",
                "mod",
                "err",
                "devS"
            };
            StreamWriter writer = new StreamWriter(OUTPUT_FILENAME);
            writer.WriteLine(string.Join(",", headers));

            string remoteMessageStr = string.Join(",",
                remoteMessage.operation,
                remoteMessage.DeviceID,
                remoteMessage.CustomerCode,
                remoteMessage.Date.Add(remoteMessage.GetTime()),
                remoteMessage.NOP
                );

            string content = string.Join(",", 
                remoteMessage.content.First().machineId,
                remoteMessage.content.First().den,
                remoteMessage.content.First().curr,
                remoteMessage.content.First().qty,
                remoteMessage.content.First().type,
                remoteMessage.content.First().N,
                remoteMessage.content.First().sType
                );

            foreach(Device device in remoteMessage.devices)
            {
                string deviceStr = string.Join(",",
                    device.name,
                    device.machineId,
                    device.mod,
                    device.err,
                    device.devS
                    );

                writer.WriteLine(string.Join(",", remoteMessageStr, content, deviceStr));
            }


            writer.Flush();
            writer.Close();


        }
    }
    public class RemoteMessage
    {
        [XmlAttribute()]
        public string operation { get; set; }
        [XmlAttribute()]
        public string DeviceID { get; set; }
        [XmlAttribute()]
        public string CustomerCode { get; set; }
        [XmlAttribute()]
        public DateTime Date { get; set; }
        
        [XmlAttribute()]
        private TimeSpan _time { get; set; }
        [XmlAttribute()]
        public DateTime Time 
        {
            get { return new DateTime().Add(_time); }
            set { _time = value.TimeOfDay; } 
        }
        [XmlAttribute()]
        public int  NOP { get; set; }

        [XmlArray("content")]
        [XmlArrayItem("count")]
        public List<Content> content { get; set; }
        [XmlArray("devStatus")]
        [XmlArrayItem("dev")]
        public List<Device> devices { get; set; }

        public TimeSpan GetTime()
        {
            return _time;
        }

    }
    public class Content
    {
        [XmlAttribute()]
        public int machineId { get; set; }
        [XmlAttribute()]
        public decimal den { get; set; }
        [XmlAttribute()]
        public string curr { get; set; }
        [XmlAttribute()]
        public int qty { get; set; }
        [XmlAttribute()]
        public string type { get; set; }
        [XmlAttribute()]
        public int N { get; set; }
        [XmlAttribute()]
        public string sType { get; set; }
    }
    public class Device
    {
        [XmlAttribute()]
        public string name { get; set; }
        [XmlAttribute()]
        public int machineId { get; set; }
        [XmlAttribute()]
        public string mod { get; set; }
        [XmlAttribute()]
        public string err { get; set; }
        [XmlAttribute()]
        public string devS { get; set; }
    }

}
 

Комментарии:

1. Вау, большое вам спасибо, я интегрировал это в «Приложение формы» и создал три класса. Документ создается, но остается пустым. Затем создается Excel с защитой от записи. Есть идеи?

2. Я протестировал его с помощью консольного приложения, и все работает нормально. Однако при использовании приложения формы созданный документ остается пустым. Сообщения об ошибке нет. Есть идеи?

3. Нет никакой разницы в запуске этого кода в форме или консоли. Поставьте точку останова и убедитесь, что код выполняется. Убедитесь, что вы читаете правильный XML-файл.

4. Я позволяю отображаемому XML-файлу отображаться в текстовом поле, поэтому я могу быть уверен, что он будет прочитан правильно. Пути одинаковы для обоих приложений. Код также абсолютно идентичен. Я не могу объяснить, почему вывод выводится с помощью консоли, а не с помощью формы.

5. Я нашел проблему. Теперь все идет так, как должно. Большое спасибо!!