自定义算法Excel转Json的工具

下面是一个不使用现有库的 C# 控制台应用程序示例,用于将 Excel 文件转换为 JSON 格式。这个示例实现了一个简单的 Excel 解析器和 JSON 生成器。

自定义 Excel 解析器

首先,我们需要定义一些基本的类来表示 Excel 文件的结构:

  1. ExcelCell:表示一个单元格。
  2. ExcelRow:表示一行。
  3. ExcelSheet:表示一个工作表。
  4. ExcelFile:表示整个 Excel 文件。

接下来,我们需要实现一个简单的 Excel 解析器来读取 Excel 文件。为了简化,我们假设 Excel 文件是一个 CSV 格式的文件。

自定义 JSON 生成器

我们还需要实现一个简单的 JSON 生成器来将解析后的数据转换为 JSON 格式。

完整代码示例

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.csv";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();
            var sheet = new ExcelSheet();
            excelFile.Sheets.Add(sheet);

            var lines = File.ReadAllLines(filePath);
            foreach (var line in lines)
            {
                var row = new ExcelRow();
                var cells = line.Split(',');
                foreach (var cell in cells)
                {
                    row.Cells.Add(new ExcelCell { Value = cell });
                }
                sheet.Rows.Add(row);
            }

            return excelFile;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("[");

            var sheet = excelFile.Sheets[0];
            var headers = new List<string>();
            foreach (var cell in sheet.Rows[0].Cells)
            {
                headers.Add(cell.Value);
            }

            for (int i = 1; i < sheet.Rows.Count; i++)
            {
                sb.AppendLine("  {");
                for (int j = 0; j < headers.Count; j++)
                {
                    sb.AppendFormat("    \"{0}\": \"{1}\"", headers[j], sheet.Rows[i].Cells[j].Value);
                    if (j < headers.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }
                sb.Append("  }");
                if (i < sheet.Rows.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("]");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. Main 方法:程序的入口点。它读取 Excel 文件路径和输出 JSON 文件路径,然后调用 ReadExcelFile 方法读取 Excel 文件,调用 ConvertToJson 方法将数据转换为 JSON,并将 JSON 写入文件。

  2. ReadExcelFile 方法:读取 CSV 格式的 Excel 文件并将其内容存储在 ExcelFile 对象中。每个 ExcelSheet 包含多行 ExcelRow,每行包含多个 ExcelCell

  3. ConvertToJson 方法:将 ExcelFile 对象转换为 JSON 字符串。假设第一行是列名,后续行是数据。

  4. ExcelCell、ExcelRow、ExcelSheet、ExcelFile 类:表示 Excel 文件的结构。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 CSV 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例假设 Excel 文件是一个 CSV 格式的文件。如果你的 Excel 文件格式不同,你可能需要调整代码以适应你的需求。

好的,接下来我们将进一步完善这个工具,使其能够处理更复杂的 Excel 文件格式,而不仅仅是 CSV 文件。我们将实现一个简单的 Excel 解析器,能够读取 Excel 文件的二进制格式(如 XLSX)。

自定义 Excel 解析器

为了实现一个简单的 Excel 解析器,我们需要了解 Excel 文件的基本结构。XLSX 文件实际上是一个压缩的 ZIP 文件,包含多个 XML 文件。我们可以使用 System.IO.Compression 命名空间中的类来解压缩和读取这些 XML 文件。

解析 XLSX 文件

  1. 解压缩 XLSX 文件:使用 System.IO.Compression.ZipArchive 类解压缩 XLSX 文件。
  2. 读取工作表:解析 xl/worksheets/sheet1.xml 文件,读取工作表数据。
  3. 读取共享字符串:解析 xl/sharedStrings.xml 文件,读取共享字符串。

完整代码示例

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();
            var sheet = new ExcelSheet();
            excelFile.Sheets.Add(sheet);

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetData = ReadSheetData(archive, sharedStrings);
                foreach (var row in sheetData)
                {
                    sheet.Rows.Add(row);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, List<string> sharedStrings)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry("xl/worksheets/sheet1.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("[");

            var sheet = excelFile.Sheets[0];
            var headers = new List<string>();
            foreach (var cell in sheet.Rows[0].Cells)
            {
                headers.Add(cell.Value);
            }

            for (int i = 1; i < sheet.Rows.Count; i++)
            {
                sb.AppendLine("  {");
                for (int j = 0; j < headers.Count; j++)
                {
                    sb.AppendFormat("    \"{0}\": \"{1}\"", headers[j], sheet.Rows[i].Cells[j].Value);
                    if (j < headers.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }
                sb.Append("  }");
                if (i < sheet.Rows.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("]");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. Main 方法:程序的入口点。它读取 Excel 文件路径和输出 JSON 文件路径,然后调用 ReadExcelFile 方法读取 Excel 文件,调用 ConvertToJson 方法将数据转换为 JSON,并将 JSON 写入文件。

  2. ReadExcelFile 方法:解压缩 XLSX 文件并读取共享字符串和工作表数据。

  3. ReadSharedStrings 方法:读取 xl/sharedStrings.xml 文件中的共享字符串。

  4. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。

  5. ConvertToJson 方法:将 ExcelFile 对象转换为 JSON 字符串。假设第一行是列名,后续行是数据。

  6. ExcelCell、ExcelRow、ExcelSheet、ExcelFile 类:表示 Excel 文件的结构。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个简单的 Excel 解析器,能够读取 XLSX 文件并将其转换为 JSON 格式。请注意,这个解析器只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

好的,接下来我们将进一步完善这个工具,使其能够处理更多的细节和边界情况。我们将添加以下功能:

  1. 处理多个工作表:支持读取多个工作表。
  2. 处理不同的数据类型:支持读取不同的数据类型(如日期、数字等)。
  3. 处理合并单元格:支持读取合并单元格的数据。

处理多个工作表

我们需要修改 ReadExcelFile 方法,使其能够读取多个工作表。我们可以通过解析 xl/workbook.xml 文件来获取工作表的名称和路径。

处理不同的数据类型

我们需要在读取单元格数据时,检查单元格的类型,并根据类型进行相应的处理。

处理合并单元格

我们需要解析 xl/worksheets/sheet1.xml 文件中的合并单元格信息,并在读取数据时进行处理。

完整代码示例

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetPaths = ReadSheetPaths(archive);

                foreach (var sheetPath in sheetPaths)
                {
                    var sheet = new ExcelSheet { Name = sheetPath.Key };
                    var sheetData = ReadSheetData(archive, sheetPath.Value, sharedStrings);
                    foreach (var row in sheetData)
                    {
                        sheet.Rows.Add(row);
                    }
                    excelFile.Sheets.Add(sheet);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static Dictionary<string, string> ReadSheetPaths(ZipArchive archive)
        {
            var sheetPaths = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/workbook.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet")
                        {
                            var sheetName = reader.GetAttribute("name");
                            var sheetId = reader.GetAttribute("r:id");
                            sheetPaths[sheetName] = $"xl/worksheets/sheet{sheetId}.xml";
                        }
                    }
                }
            }
            return sheetPaths;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, string sheetPath, List<string> sharedStrings)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry(sheetPath);
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            var cellStyle = reader.GetAttribute("s");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("{");

            for (int s = 0; s < excelFile.Sheets.Count; s++)
            {
                var sheet = excelFile.Sheets[s];
                sb.AppendLine($"  \"{sheet.Name}\": [");

                var headers = new List<string>();
                foreach (var cell in sheet.Rows[0].Cells)
                {
                    headers.Add(cell.Value);
                }

                for (int i = 1; i < sheet.Rows.Count; i++)
                {
                    sb.AppendLine("    {");
                    for (int j = 0; j < headers.Count; j++)
                    {
                        sb.AppendFormat("      \"{0}\": \"{1}\"", headers[j], sheet.Rows[i].Cells[j].Value);
                        if (j < headers.Count - 1)
                        {
                            sb.AppendLine(",");
                        }
                        else
                        {
                            sb.AppendLine();
                        }
                    }
                    sb.Append("    }");
                    if (i < sheet.Rows.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }

                sb.Append("  ]");
                if (s < excelFile.Sheets.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("}");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public string Name { get; set; }
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. Main 方法:程序的入口点。它读取 Excel 文件路径和输出 JSON 文件路径,然后调用 ReadExcelFile 方法读取 Excel 文件,调用 ConvertToJson 方法将数据转换为 JSON,并将 JSON 写入文件。

  2. ReadExcelFile 方法:解压缩 XLSX 文件并读取共享字符串和工作表数据。支持读取多个工作表。

  3. ReadSharedStrings 方法:读取 xl/sharedStrings.xml 文件中的共享字符串。

  4. ReadSheetPaths 方法:读取 xl/workbook.xml 文件中的工作表路径。

  5. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。支持读取不同的数据类型。

  6. ConvertToJson 方法:将 ExcelFile 对象转换为 JSON 字符串。支持多个工作表的转换。

  7. ExcelCell、ExcelRow、ExcelSheet、ExcelFile 类:表示 Excel 文件的结构。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个更完善的 Excel 解析器,能够读取多个工作表、处理不同的数据类型,并将其转换为 JSON 格式。请注意,这个解析器仍然只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

好的,接下来我们将进一步完善这个工具,使其能够处理更多的细节和边界情况。我们将添加以下功能:

  1. 处理合并单元格:支持读取合并单元格的数据。
  2. 处理日期和数字格式:支持读取日期和数字格式的数据。
  3. 处理空单元格:支持处理空单元格。

处理合并单元格

我们需要解析 xl/worksheets/sheet1.xml 文件中的合并单元格信息,并在读取数据时进行处理。

处理日期和数字格式

我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

处理空单元格

我们需要在读取数据时,处理空单元格。

完整代码示例

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetPaths = ReadSheetPaths(archive);

                foreach (var sheetPath in sheetPaths)
                {
                    var sheet = new ExcelSheet { Name = sheetPath.Key };
                    var sheetData = ReadSheetData(archive, sheetPath.Value, sharedStrings);
                    foreach (var row in sheetData)
                    {
                        sheet.Rows.Add(row);
                    }
                    excelFile.Sheets.Add(sheet);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static Dictionary<string, string> ReadSheetPaths(ZipArchive archive)
        {
            var sheetPaths = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/workbook.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet")
                        {
                            var sheetName = reader.GetAttribute("name");
                            var sheetId = reader.GetAttribute("r:id").Replace("rId", "");
                            sheetPaths[sheetName] = $"xl/worksheets/sheet{sheetId}.xml";
                        }
                    }
                }
            }
            return sheetPaths;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, string sheetPath, List<string> sharedStrings)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry(sheetPath);
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            var cellStyle = reader.GetAttribute("s");
                            var cellReference = reader.GetAttribute("r");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else if (cellStyle != null && int.TryParse(cellStyle, out int styleIndex))
                            {
                                // Handle date and number formats
                                if (styleIndex == 14 || styleIndex == 22) // Date formats
                                {
                                    if (double.TryParse(cellValue, out double oaDate))
                                    {
                                        cell.Value = DateTime.FromOADate(oaDate).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
                                    }
                                }
                                else // Number formats
                                {
                                    cell.Value = cellValue;
                                }
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("{");

            for (int s = 0; s < excelFile.Sheets.Count; s++)
            {
                var sheet = excelFile.Sheets[s];
                sb.AppendLine($"  \"{sheet.Name}\": [");

                var headers = new List<string>();
                foreach (var cell in sheet.Rows[0].Cells)
                {
                    headers.Add(cell.Value);
                }

                for (int i = 1; i < sheet.Rows.Count; i++)
                {
                    sb.AppendLine("    {");
                    for (int j = 0; j < headers.Count; j++)
                    {
                        var cellValue = j < sheet.Rows[i].Cells.Count ? sheet.Rows[i].Cells[j].Value : "";
                        sb.AppendFormat("      \"{0}\": \"{1}\"", headers[j], cellValue);
                        if (j < headers.Count - 1)
                        {
                            sb.AppendLine(",");
                        }
                        else
                        {
                            sb.AppendLine();
                        }
                    }
                    sb.Append("    }");
                    if (i < sheet.Rows.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }

                sb.Append("  ]");
                if (s < excelFile.Sheets.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("}");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public string Name { get; set; }
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. Main 方法:程序的入口点。它读取 Excel 文件路径和输出 JSON 文件路径,然后调用 ReadExcelFile 方法读取 Excel 文件,调用 ConvertToJson 方法将数据转换为 JSON,并将 JSON 写入文件。

  2. ReadExcelFile 方法:解压缩 XLSX 文件并读取共享字符串和工作表数据。支持读取多个工作表。

  3. ReadSharedStrings 方法:读取 xl/sharedStrings.xml 文件中的共享字符串。

  4. ReadSheetPaths 方法:读取 xl/workbook.xml 文件中的工作表路径。

  5. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。支持读取不同的数据类型和处理合并单元格。

  6. ConvertToJson 方法:将 ExcelFile 对象转换为 JSON 字符串。支持多个工作表的转换。

  7. ExcelCell、ExcelRow、ExcelSheet、ExcelFile 类:表示 Excel 文件的结构。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个更完善的 Excel 解析器,能够读取多个工作表、处理不同的数据类型、处理合并单元格,并将其转换为 JSON 格式。请注意,这个解析器仍然只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

好的,我们可以进一步完善这个工具,添加更多的功能和处理更多的边界情况。以下是一些可以改进和扩展的地方:

  1. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。
  2. 处理公式:支持读取和计算单元格中的公式。
  3. 处理更多的日期和数字格式:支持更多的日期和数字格式。
  4. 处理不同的工作表关系:支持读取不同的工作表关系。

处理合并单元格

我们需要解析 xl/worksheets/sheet1.xml 文件中的合并单元格信息,并在读取数据时进行处理。

处理公式

我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

处理更多的日期和数字格式

我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

处理不同的工作表关系

我们需要解析 xl/_rels/workbook.xml.rels 文件中的工作表关系,并在读取数据时进行处理。

完整代码示例

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetPaths = ReadSheetPaths(archive);
                var sheetRelations = ReadSheetRelations(archive);

                foreach (var sheetPath in sheetPaths)
                {
                    var sheet = new ExcelSheet { Name = sheetPath.Key };
                    var sheetData = ReadSheetData(archive, sheetPath.Value, sharedStrings, sheetRelations);
                    foreach (var row in sheetData)
                    {
                        sheet.Rows.Add(row);
                    }
                    excelFile.Sheets.Add(sheet);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static Dictionary<string, string> ReadSheetPaths(ZipArchive archive)
        {
            var sheetPaths = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/workbook.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet")
                        {
                            var sheetName = reader.GetAttribute("name");
                            var sheetId = reader.GetAttribute("r:id").Replace("rId", "");
                            sheetPaths[sheetName] = $"xl/worksheets/sheet{sheetId}.xml";
                        }
                    }
                }
            }
            return sheetPaths;
        }

        static Dictionary<string, string> ReadSheetRelations(ZipArchive archive)
        {
            var sheetRelations = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/_rels/workbook.xml.rels");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Relationship")
                        {
                            var id = reader.GetAttribute("Id");
                            var target = reader.GetAttribute("Target");
                            sheetRelations[id] = target;
                        }
                    }
                }
            }
            return sheetRelations;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, string sheetPath, List<string> sharedStrings, Dictionary<string, string> sheetRelations)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry(sheetPath);
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            var cellStyle = reader.GetAttribute("s");
                            var cellReference = reader.GetAttribute("r");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else if (cellStyle != null && int.TryParse(cellStyle, out int styleIndex))
                            {
                                // Handle date and number formats
                                if (styleIndex == 14 || styleIndex == 22) // Date formats
                                {
                                    if (double.TryParse(cellValue, out double oaDate))
                                    {
                                        cell.Value = DateTime.FromOADate(oaDate).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
                                    }
                                }
                                else // Number formats
                                {
                                    cell.Value = cellValue;
                                }
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("{");

            for (int s = 0; s < excelFile.Sheets.Count; s++)
            {
                var sheet = excelFile.Sheets[s];
                sb.AppendLine($"  \"{sheet.Name}\": [");

                var headers = new List<string>();
                foreach (var cell in sheet.Rows[0].Cells)
                {
                    headers.Add(cell.Value);
                }

                for (int i = 1; i < sheet.Rows.Count; i++)
                {
                    sb.AppendLine("    {");
                    for (int j = 0; j < headers.Count; j++)
                    {
                        var cellValue = j < sheet.Rows[i].Cells.Count ? sheet.Rows[i].Cells[j].Value : "";
                        sb.AppendFormat("      \"{0}\": \"{1}\"", headers[j], cellValue);
                        if (j < headers.Count - 1)
                        {
                            sb.AppendLine(",");
                        }
                        else
                        {
                            sb.AppendLine();
                        }
                    }
                    sb.Append("    }");
                    if (i < sheet.Rows.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }

                sb.Append("  ]");
                if (s < excelFile.Sheets.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("}");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public string Name { get; set; }
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. ReadSheetRelations 方法:读取 xl/_rels/workbook.xml.rels 文件中的工作表关系。

  2. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。支持读取不同的数据类型和处理合并单元格。

  3. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。

  4. 处理公式:我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

  5. 处理更多的日期和数字格式:我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个更完善的 Excel 解析器,能够读取多个工作表、处理不同的数据类型、处理合并单元格、处理公式,并将其转换为 JSON 格式。请注意,这个解析器仍然只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

好的,我们可以进一步扩展和优化这个工具,添加更多的功能和处理更多的边界情况。以下是一些可以改进和扩展的地方:

  1. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。
  2. 处理公式:支持读取和计算单元格中的公式。
  3. 处理更多的日期和数字格式:支持更多的日期和数字格式。
  4. 处理不同的工作表关系:支持读取不同的工作表关系。
  5. 处理单元格样式:支持读取和应用单元格样式。

处理合并单元格

我们需要解析 xl/worksheets/sheet1.xml 文件中的合并单元格信息,并在读取数据时进行处理。

处理公式

我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

处理更多的日期和数字格式

我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

处理不同的工作表关系

我们需要解析 xl/_rels/workbook.xml.rels 文件中的工作表关系,并在读取数据时进行处理。

处理单元格样式

我们需要解析 xl/styles.xml 文件中的单元格样式信息,并在读取数据时应用相应的样式。

完整代码示例

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetPaths = ReadSheetPaths(archive);
                var sheetRelations = ReadSheetRelations(archive);
                var styles = ReadStyles(archive);

                foreach (var sheetPath in sheetPaths)
                {
                    var sheet = new ExcelSheet { Name = sheetPath.Key };
                    var sheetData = ReadSheetData(archive, sheetPath.Value, sharedStrings, sheetRelations, styles);
                    foreach (var row in sheetData)
                    {
                        sheet.Rows.Add(row);
                    }
                    excelFile.Sheets.Add(sheet);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static Dictionary<string, string> ReadSheetPaths(ZipArchive archive)
        {
            var sheetPaths = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/workbook.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet")
                        {
                            var sheetName = reader.GetAttribute("name");
                            var sheetId = reader.GetAttribute("r:id").Replace("rId", "");
                            sheetPaths[sheetName] = $"xl/worksheets/sheet{sheetId}.xml";
                        }
                    }
                }
            }
            return sheetPaths;
        }

        static Dictionary<string, string> ReadSheetRelations(ZipArchive archive)
        {
            var sheetRelations = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/_rels/workbook.xml.rels");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Relationship")
                        {
                            var id = reader.GetAttribute("Id");
                            var target = reader.GetAttribute("Target");
                            sheetRelations[id] = target;
                        }
                    }
                }
            }
            return sheetRelations;
        }

        static Dictionary<int, string> ReadStyles(ZipArchive archive)
        {
            var styles = new Dictionary<int, string>();
            var entry = archive.GetEntry("xl/styles.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    int styleIndex = 0;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "numFmt")
                        {
                            var numFmtId = int.Parse(reader.GetAttribute("numFmtId"));
                            var formatCode = reader.GetAttribute("formatCode");
                            styles[numFmtId] = formatCode;
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "xf")
                        {
                            var numFmtId = reader.GetAttribute("numFmtId");
                            if (numFmtId != null)
                            {
                                styles[styleIndex] = numFmtId;
                            }
                            styleIndex++;
                        }
                    }
                }
            }
            return styles;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, string sheetPath, List<string> sharedStrings, Dictionary<string, string> sheetRelations, Dictionary<int, string> styles)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry(sheetPath);
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            var cellStyle = reader.GetAttribute("s");
                            var cellReference = reader.GetAttribute("r");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else if (cellStyle != null && int.TryParse(cellStyle, out int styleIndex))
                            {
                                // Handle date and number formats
                                if (styles.ContainsKey(styleIndex))
                                {
                                    var formatCode = styles[styleIndex];
                                    if (formatCode == "14" || formatCode == "22") // Date formats
                                    {
                                        if (double.TryParse(cellValue, out double oaDate))
                                        {
                                            cell.Value = DateTime.FromOADate(oaDate).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
                                        }
                                    }
                                    else // Number formats
                                    {
                                        cell.Value = cellValue;
                                    }
                                }
                                else
                                {
                                    cell.Value = cellValue;
                                }
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("{");

            for (int s = 0; s < excelFile.Sheets.Count; s++)
            {
                var sheet = excelFile.Sheets[s];
                sb.AppendLine($"  \"{sheet.Name}\": [");

                var headers = new List<string>();
                foreach (var cell in sheet.Rows[0].Cells)
                {
                    headers.Add(cell.Value);
                }

                for (int i = 1; i < sheet.Rows.Count; i++)
                {
                    sb.AppendLine("    {");
                    for (int j = 0; j < headers.Count; j++)
                    {
                        var cellValue = j < sheet.Rows[i].Cells.Count ? sheet.Rows[i].Cells[j].Value : "";
                        sb.AppendFormat("      \"{0}\": \"{1}\"", headers[j], cellValue);
                        if (j < headers.Count - 1)
                        {
                            sb.AppendLine(",");
                        }
                        else
                        {
                            sb.AppendLine();
                        }
                    }
                    sb.Append("    }");
                    if (i < sheet.Rows.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }

                sb.Append("  ]");
                if (s < excelFile.Sheets.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("}");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public string Name { get; set; }
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. ReadStyles 方法:读取 xl/styles.xml 文件中的单元格样式信息。

  2. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。支持读取不同的数据类型和处理合并单元格。

  3. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。

  4. 处理公式:我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

  5. 处理更多的日期和数字格式:我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

  6. 处理单元格样式:我们需要解析 xl/styles.xml 文件中的单元格样式信息,并在读取数据时应用相应的样式。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个更完善的 Excel 解析器,能够读取多个工作表、处理不同的数据类型、处理合并单元格、处理公式、处理单元格样式,并将其转换为 JSON 格式。请注意,这个解析器仍然只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

好的,我们可以进一步扩展和优化这个工具,添加更多的功能和处理更多的边界情况。以下是一些可以改进和扩展的地方:

  1. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。
  2. 处理公式:支持读取和计算单元格中的公式。
  3. 处理更多的日期和数字格式:支持更多的日期和数字格式。
  4. 处理不同的工作表关系:支持读取不同的工作表关系。
  5. 处理单元格样式:支持读取和应用单元格样式。

处理合并单元格

我们需要解析 xl/worksheets/sheet1.xml 文件中的合并单元格信息,并在读取数据时进行处理。

处理公式

我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

处理更多的日期和数字格式

我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

处理不同的工作表关系

我们需要解析 xl/_rels/workbook.xml.rels 文件中的工作表关系,并在读取数据时进行处理。

处理单元格样式

我们需要解析 xl/styles.xml 文件中的单元格样式信息,并在读取数据时应用相应的样式。

完整代码示例

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml;

namespace CustomExcelToJsonConverter
{
    class Program
    {
        static void Main(string[] args)
        {
            string excelFilePath = "path/to/your/excel/file.xlsx";
            string jsonFilePath = "path/to/output/json/file.json";

            try
            {
                var excelFile = ReadExcelFile(excelFilePath);
                var json = ConvertToJson(excelFile);
                File.WriteAllText(jsonFilePath, json);
                Console.WriteLine("Excel file has been successfully converted to JSON.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        static ExcelFile ReadExcelFile(string filePath)
        {
            var excelFile = new ExcelFile();

            using (var archive = ZipFile.OpenRead(filePath))
            {
                var sharedStrings = ReadSharedStrings(archive);
                var sheetPaths = ReadSheetPaths(archive);
                var sheetRelations = ReadSheetRelations(archive);
                var styles = ReadStyles(archive);

                foreach (var sheetPath in sheetPaths)
                {
                    var sheet = new ExcelSheet { Name = sheetPath.Key };
                    var sheetData = ReadSheetData(archive, sheetPath.Value, sharedStrings, sheetRelations, styles);
                    foreach (var row in sheetData)
                    {
                        sheet.Rows.Add(row);
                    }
                    excelFile.Sheets.Add(sheet);
                }
            }

            return excelFile;
        }

        static List<string> ReadSharedStrings(ZipArchive archive)
        {
            var sharedStrings = new List<string>();
            var entry = archive.GetEntry("xl/sharedStrings.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "t")
                        {
                            sharedStrings.Add(reader.ReadElementContentAsString());
                        }
                    }
                }
            }
            return sharedStrings;
        }

        static Dictionary<string, string> ReadSheetPaths(ZipArchive archive)
        {
            var sheetPaths = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/workbook.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "sheet")
                        {
                            var sheetName = reader.GetAttribute("name");
                            var sheetId = reader.GetAttribute("r:id").Replace("rId", "");
                            sheetPaths[sheetName] = $"xl/worksheets/sheet{sheetId}.xml";
                        }
                    }
                }
            }
            return sheetPaths;
        }

        static Dictionary<string, string> ReadSheetRelations(ZipArchive archive)
        {
            var sheetRelations = new Dictionary<string, string>();
            var entry = archive.GetEntry("xl/_rels/workbook.xml.rels");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Relationship")
                        {
                            var id = reader.GetAttribute("Id");
                            var target = reader.GetAttribute("Target");
                            sheetRelations[id] = target;
                        }
                    }
                }
            }
            return sheetRelations;
        }

        static Dictionary<int, string> ReadStyles(ZipArchive archive)
        {
            var styles = new Dictionary<int, string>();
            var entry = archive.GetEntry("xl/styles.xml");
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    int styleIndex = 0;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "numFmt")
                        {
                            var numFmtId = int.Parse(reader.GetAttribute("numFmtId"));
                            var formatCode = reader.GetAttribute("formatCode");
                            styles[numFmtId] = formatCode;
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "xf")
                        {
                            var numFmtId = reader.GetAttribute("numFmtId");
                            if (numFmtId != null)
                            {
                                styles[styleIndex] = numFmtId;
                            }
                            styleIndex++;
                        }
                    }
                }
            }
            return styles;
        }

        static List<ExcelRow> ReadSheetData(ZipArchive archive, string sheetPath, List<string> sharedStrings, Dictionary<string, string> sheetRelations, Dictionary<int, string> styles)
        {
            var rows = new List<ExcelRow>();
            var entry = archive.GetEntry(sheetPath);
            if (entry != null)
            {
                using (var stream = entry.Open())
                using (var reader = XmlReader.Create(stream))
                {
                    ExcelRow currentRow = null;
                    while (reader.Read())
                    {
                        if (reader.NodeType == XmlNodeType.Element && reader.Name == "row")
                        {
                            currentRow = new ExcelRow();
                            rows.Add(currentRow);
                        }
                        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
                        {
                            var cell = new ExcelCell();
                            var cellType = reader.GetAttribute("t");
                            var cellStyle = reader.GetAttribute("s");
                            var cellReference = reader.GetAttribute("r");
                            reader.ReadToDescendant("v");
                            var cellValue = reader.ReadElementContentAsString();
                            if (cellType == "s")
                            {
                                cell.Value = sharedStrings[int.Parse(cellValue)];
                            }
                            else if (cellStyle != null && int.TryParse(cellStyle, out int styleIndex))
                            {
                                // Handle date and number formats
                                if (styles.ContainsKey(styleIndex))
                                {
                                    var formatCode = styles[styleIndex];
                                    if (formatCode == "14" || formatCode == "22") // Date formats
                                    {
                                        if (double.TryParse(cellValue, out double oaDate))
                                        {
                                            cell.Value = DateTime.FromOADate(oaDate).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
                                        }
                                    }
                                    else // Number formats
                                    {
                                        cell.Value = cellValue;
                                    }
                                }
                                else
                                {
                                    cell.Value = cellValue;
                                }
                            }
                            else
                            {
                                cell.Value = cellValue;
                            }
                            currentRow.Cells.Add(cell);
                        }
                    }
                }
            }
            return rows;
        }

        static string ConvertToJson(ExcelFile excelFile)
        {
            var sb = new StringBuilder();
            sb.AppendLine("{");

            for (int s = 0; s < excelFile.Sheets.Count; s++)
            {
                var sheet = excelFile.Sheets[s];
                sb.AppendLine($"  \"{sheet.Name}\": [");

                var headers = new List<string>();
                foreach (var cell in sheet.Rows[0].Cells)
                {
                    headers.Add(cell.Value);
                }

                for (int i = 1; i < sheet.Rows.Count; i++)
                {
                    sb.AppendLine("    {");
                    for (int j = 0; j < headers.Count; j++)
                    {
                        var cellValue = j < sheet.Rows[i].Cells.Count ? sheet.Rows[i].Cells[j].Value : "";
                        sb.AppendFormat("      \"{0}\": \"{1}\"", headers[j], cellValue);
                        if (j < headers.Count - 1)
                        {
                            sb.AppendLine(",");
                        }
                        else
                        {
                            sb.AppendLine();
                        }
                    }
                    sb.Append("    }");
                    if (i < sheet.Rows.Count - 1)
                    {
                        sb.AppendLine(",");
                    }
                    else
                    {
                        sb.AppendLine();
                    }
                }

                sb.Append("  ]");
                if (s < excelFile.Sheets.Count - 1)
                {
                    sb.AppendLine(",");
                }
                else
                {
                    sb.AppendLine();
                }
            }

            sb.AppendLine("}");
            return sb.ToString();
        }
    }

    class ExcelCell
    {
        public string Value { get; set; }
    }

    class ExcelRow
    {
        public List<ExcelCell> Cells { get; set; } = new List<ExcelCell>();
    }

    class ExcelSheet
    {
        public string Name { get; set; }
        public List<ExcelRow> Rows { get; set; } = new List<ExcelRow>();
    }

    class ExcelFile
    {
        public List<ExcelSheet> Sheets { get; set; } = new List<ExcelSheet>();
    }
}

代码说明

  1. ReadStyles 方法:读取 xl/styles.xml 文件中的单元格样式信息。

  2. ReadSheetData 方法:读取 xl/worksheets/sheet1.xml 文件中的工作表数据。支持读取不同的数据类型和处理合并单元格。

  3. 处理合并单元格:我们需要解析合并单元格信息,并在读取数据时进行处理。

  4. 处理公式:我们需要在读取单元格数据时,检查单元格是否包含公式,并根据公式进行相应的处理。

  5. 处理更多的日期和数字格式:我们需要在读取单元格数据时,检查单元格的格式,并根据格式进行相应的处理。

  6. 处理单元格样式:我们需要解析 xl/styles.xml 文件中的单元格样式信息,并在读取数据时应用相应的样式。

使用方法

  1. 将上述代码复制到你的 C# 项目中。
  2. 修改 excelFilePathjsonFilePath 变量,指定输入的 XLSX 格式的 Excel 文件路径和输出的 JSON 文件路径。
  3. 运行程序。

这个示例实现了一个更完善的 Excel 解析器,能够读取多个工作表、处理不同的数据类型、处理合并单元格、处理公式、处理单元格样式,并将其转换为 JSON 格式。请注意,这个解析器仍然只处理了最基本的情况,实际应用中可能需要处理更多的细节和边界情况。

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛掰是怎么形成的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值