Проблема с преобразованием текста stramreader, содержащего XML данных, когда есть разрыв строки - PullRequest
1 голос
/ 18 июня 2020
  1. У меня есть файл журнала, содержащий строки смешивания, такие как XML и Jason.
  2. Я должен извлечь каждую из них, чтобы получить желаемый результат.
  3. Элемент xml_string содержит который может иметь разрыв строки.
  4. Я сначала читаю все строки, а затем разрываю их, используя Environment.NewLine, чтобы получить log_file_lines, а затем получаю строки в IEnumerable для xml_lines и jason_lines.
  5. Однако проблема возникает, когда в xml_lines есть новая строка. Это означает, что я получаю половину или неформатированные строки xml_ в поле.
  6. Есть ли способ в регулярном выражении или удалить эти строки из самого текста log_file_string, а затем передать t в log_file_lines?
  7. Другой опция может получать данные только между узлами и в xml_lines из log_file_string с использованием регулярного выражения без цикла, поскольку данные имеют размер файла 3 МБ: (

вот как появляется log_file_string:

2020-06-10T10:58:07.0792762Z [data_type_jason] {"person_id":"101", "order_id":"123"}
2020-06-12T10:58:07.0792762Z [data_type_xml] <?xml version="1.0"?><persons><person id = "101"><name>"Thomas Edison"</name><age>"35"</age><phone>"7777777777"</phone><address>"62  Ross Road, 
    MARSHAM, NR10 6EA"</address><country>"England"</country></person></persons>
2020-06-13T10:58:07.0792762Z [data_type_jason]  {"person_id":"102", "order_id":"140"}
2020-06-14T10:58:07.0792762Z [data_type_xml]<?xml version="1.0"?><persons><person id = "102"><name>"Louis Pasture"</name><age>"40"</age><phone>"99999999"</phone><address>"145  Thames Street, BOOSBECK, TS12 1AN"</address><country>"England"</country></person></persons>

Вот полный прототип младенца:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }//Form1

        private void Form1_Load(object sender, EventArgs e)
        {
            String file_folder = @"X:\VS 2019\C Sharp\Test";
            String file_path = Path.Combine(file_folder, "log_file.txt");
            process_log_file_data(file_folder, file_path);
        }//Form1_Load

        private void process_log_file_data(String file_folder, String file_path)
        {
            String log_file_string = read_all_lines_from_file(file_folder, file_path);
            String[] log_file_lines = log_file_string.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);

            //The other option can be getting data between just to nodes <persons> and </persons> in xml_lines from the log_file_string using regex but am not regex savvy :(
            IEnumerable<String> xml_lines = from line in log_file_lines
                                            where line.Contains("data_type_xml")
                                            select line;

            IEnumerable<String> jason_lines = from line in log_file_lines
                                              where line.Contains("data_type_jason")
                                              select line;

            XDocument xml_document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("xml_data"));

            foreach (var xml_line in xml_lines)
            {
                String line = xml_line.Split(new String[] { "[data_type_xml]" }, StringSplitOptions.None)[xml_line.Split(new String[] { "[data_type_xml]" }, StringSplitOptions.None).GetUpperBound(0)].Trim();

            //here is the issue < persond id = "101" >< address > as the  there is a line break in log_file_lines  the xml_line = 2020-06-12T10:58:07.0792762Z [data_type_xml] <?xml version="1.0"?><person><person id = "101"><name>"Thomas Edison"<name><age>"35"</age><phone>"7777777777"</phone><address>"62  Ross Road
            XDocument temp_xml_document = XDocument.Parse(line); //Unexpected end of file has occurred. The following elements are not closed: address, person, persons. Line 1, position 144.'
            }

            foreach (var jason_line in jason_lines)
            {
                //do something
            }
        }//process_log_file_data(String file_folder, String file_path)

        private String read_all_lines_from_file(String file_folder, String file_path)
        {
            FileInfo file_info = new FileInfo(file_path);
            if ((!file_info.Exists) || (file_info.Length == 0))
            {
                return String.Empty;
            }

            FileStream file_stream; StreamReader stream_reader; UTF8Encoding utf8_encoding; String file_text;
            file_stream = new FileStream(file_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            utf8_encoding = new UTF8Encoding(false);
            stream_reader = new StreamReader(file_stream, utf8_encoding);
            file_text = stream_reader.ReadToEnd();
            stream_reader.Close();
            file_stream.Close();
            return file_text;
        }//read_all_lines_from_file

    }//Form1 : Form

}//Test

Ответы [ 2 ]

0 голосов
/ 18 июня 2020

Используя рекурсию и streamreader, этого можно добиться следующим образом. Идея заключается в одновременном чтении двух строк чтения с несколькими условиями как ...

class Program
{
    static void Main(string[] args)
    {
        using (StreamReader r = new StreamReader("filename"))
        {
            while (!r.EndOfStream)
            {
                var fline = r.ReadLine();
                string sline = "";
                if (!r.EndOfStream)
                    sline = r.ReadLine();

                RecursivelyParse(r,ref fline, ref sline);
            }
        }
    }

    private static void RecursivelyParse(StreamReader r, ref string fline, ref string sline)
    {
        if (fline.Contains("data_type_xml"))
        {
            if (!(sline.Contains("data_type_xml") || sline.Contains("data_type_jason")) && sline != "")
            {
                fline += sline;
                sline = "";
                //Next line also a part of xml
                //parsing loggic of line containing  xml 
            }
            else
            {
                //parsing loggic of line containing  xml 
            }
        }
        else if (fline.Contains("data_type_jason"))
        {
            //parsing loggic of line containing  jason 
        }

        if (sline.Contains("data_type_xml"))
        {
            if (!r.EndOfStream)
                fline = r.ReadLine();
            else
                fline = "";

            if (!(fline.Contains("data_type_xml") || fline.Contains("data_type_jason")) && fline != "")
            {
                sline += fline;
                fline = "";
                //Next line also a part of xml
                //parsing loggic of line containing  xml 
            }
            else
            {
                //parsing loggic of line containing  xml 
            }
        }
        else if (sline.Contains("data_type_jason"))
        {
            //parsing loggic of line containing  jason 
        }

        while (!r.EndOfStream)
        {
            fline = r.ReadLine();

            if (!r.EndOfStream)
                sline = r.ReadLine();
            else 
                sline = "";

            RecursivelyParse(r, ref fline, ref sline);
        }
    }

}
0 голосов
/ 18 июня 2020

Разбор записей журнала:

Попробуйте что-то вроде этого:

public static IList<string> ParseLogs(string log_file_string)
{
    // The pattern of the beginning of each log entry
    var logprefixPattern = @"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z \[data_type_(jason|xml)\] ";

    // Replace it with a symbol
    var splitPattern = "[log_entry]";
    var replaced = Regex.Replace(log_file_string, logprefixPattern, splitPattern);

    // Split the string with that symbol
    var splited = replaced.Split(splitPattern);

    // Now you get the list of logs.
    return splited;
}

Моя идея заключается в том, что вы читаете все содержимое и сохраняете его в переменной log_file_string, вы можете посмотреть для шаблона каждого журнала вместо того, чтобы читать его построчно.

Похоже, что каждая запись журнала начинается с одного и того же шаблона, поэтому вы можете разделить запись журнала по этому шаблону.

Если вы хотите разделить элементы на 2 группы: xml журналы и json журналы, вы можете oop разделить результаты один за другим и определить их, например, по начальному символу ({ равно json и < - это xml).

Анализ XML внутри записи журнала

Предполагается, что вы хотите преобразовать XML в список json строк и каждая строка - это человек, вы можете использовать Newtonsoft.Json:

public static IList<string> ParseXml(string xmlStr)
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xmlStr);

    // assuming that each entry contains at least 1 person, and you want to extract those persons
    var ppl = doc.GetElementsByTagName("person");
    var results = new List<string>{};
    foreach(XmlNode p in ppl)
    {
        string jsonStr = Newtonsoft.Json.JsonConvert.SerializeXmlNode(p);
        results.Add(jsonStr);       
    }
    return results;
}

Для простоты я просто возвращаю здесь json строки. Вы можете десериализовать jsonStr в некоторую модель C#, которую вы определили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...