如何识别单词表中合并的行和列? [英] How to identify merged column and row in word table?

查看:70
本文介绍了如何识别单词表中合并的行和列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从表格中读取所有文本.通过使用下面的内容,我可以从表中读取内容. https://1drv.ms/w/s!Ah-Jh2Ok5SuHel9ZpB-V5DZ66DM在这里,我上传了一个带有表格的Docx虚拟文件.

I need to read all the text from a table. By using below I can read the content from table. https://1drv.ms/w/s!Ah-Jh2Ok5SuHel9ZpB-V5DZ66DM here I uploaded a dummy Docx file having tables.

foreach (Word.Row row in tb.Rows)
{
    foreach (Word.Cell cell in row.Cells)
    {
        string cellText = "";
        if (cell.Range != null)
        {
            cellText = cell.Range.Text.ToString().Trim().Replace("\r\a", "");
        }
    }
} 

但在以下3种情况下,我会遇到问题.

But for below 3 cases I face problem.

    情况1:如表1所示,两个列单元格合并在一起.通过使用上面的代码,我可以读取所有值,但是与其他行相比,它的迭代次数少.在这里,我如何识别该行是否已合并单元格?
  • 情况2:如表2所示,此处合并了2行.在迭代时,我从tb.Rows得到以下错误 由于表具有垂直合并的单元格,因此无法访问此集合中的单个行. 在这里如何识别表是否已合并行?
  • 情况3:显示在表3中.这里的表在表内部.通过使用上面的代码,它仅识别一个表和cellText = cell.Range.Text.ToString().Trim().Replace("\r\a", "");在此行的结尾,执行cellText获取当前单元格的所有值+内部表单元格的值.即2abcd.在这里,我如何迭代内部表?
  • Case 1: Showing in Table 1, two column cells were merged. By using above code I am able to read the all the values but it has one less iteration as compared to other rows. Here how can I identify whether that row has merged cell/s?
  • Case 2:Showing in Table 2, here 2 rows were merged. While iterating I get below error from tb.Rows Cannot access individual rows in this collection because the table has vertically merged cells. Here how can I identify whether a table have merged row or not?
  • Case 3: Showing in Table 3. Here a table is inside a table. By using above code it identify only one table and cellText = cell.Range.Text.ToString().Trim().Replace("\r\a", ""); at the end of this lines execution cellText get all the values of the current cell + inner table cell values. i.e. 2abcd. Here How can I iterate inner tables?

推荐答案

您可以通过查看表的XML来检测是否合并了单元格.我放在一起的这个示例分析XML表,然后找到相应的互操作单元.一切都变成二维数组,然后打印出来.

You can detect whether cells are merged by looking at the XML of the table. This example that I put together analyses the XML table and then finds the corresponding interop Cells. Everything is turned into a twodimensional array which is then printed.

希望这是一个好的开始.

Hopefully it's a good start.

using System;
using System.Linq;
using System.Xml.Linq;
using Word = NetOffice.WordApi;

namespace TableTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (var app = Word.Application.GetActiveInstance())
                {
                    var document = app.ActiveDocument;
                    var documentTitle = $"* Tables in {document.Name} *";
                    Console.WriteLine(new string('*', documentTitle.Length));
                    Console.WriteLine(documentTitle);
                    Console.WriteLine(new string('*', documentTitle.Length));
                    Console.WriteLine();


                    for (int i = 1; i <= document.Tables.Count; i++)
                    {
                        var table = document.Tables[i];

                        var tableTitle = $"Table #{i}";

                        Console.WriteLine(tableTitle);
                        Console.WriteLine(new string('-', tableTitle.Length));

                        foreach (var cellInfo in CellInfo.GetInfosFromTable(table))
                        {
                            Console.WriteLine(" - " + cellInfo);
                        }

                        Console.WriteLine();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            Console.WriteLine();
            Console.WriteLine("Done executing!");
            Console.ReadLine();
        }

        class CellInfo
        {
            public Word.Cell Cell { get; set; }
            public XElement XmlCell { get; set; }
            public int XmlRow { get; set; }
            public int XmlColumn { get; set; }
            public int Row { get; set; }
            public int Column { get; set; }
            public XElement MergedHorizontallyWith { get; set; }
            public XElement MergedVerticallyWith { get; set; }

            public override string ToString()
            {
                if (MergedHorizontallyWith == null && MergedVerticallyWith == null)
                {
                    var range = Cell?.Range;

                    var interopText = string.Empty;

                    if (!Equals(range, null))
                    {
                        interopText = range.Text;

                        //\r\a marks the end of a cell, \r and \n are normal line breaks
                        interopText = interopText.Replace("\r\a", "<>").Replace("\r", "\\r").Replace("\n", "\\n");

                        //Remove the last cell ending marker (it's always there)
                        if (interopText.EndsWith("<>"))
                            interopText = interopText.Substring(0, interopText.Length - 2);
                    }

                    return $"xml: {Row}, {Column} (interop: {XmlRow}, {XmlColumn}): {XmlCell?.Value ?? string.Empty} = {interopText}";
                }
                else if (MergedHorizontallyWith != null)
                {
                    return $"xml: {Row}, {Column} (interop: {XmlRow}, {XmlColumn}): MERGED HORIZONTALLY";
                }
                else if (MergedVerticallyWith != null)
                {
                    return $"xml: {Row}, {Column} (interop: {XmlRow}, {XmlColumn}): MERGED VERTICALLY";
                }
                else
                {
                    return $"xml: {Row}, {Column} (interop: {XmlRow}, {XmlColumn}): this shouldn't happen";

                }
            }

            public static CellInfo[,] GetInfosFromTable(Word.Table table)
            {
                var doc = XDocument.Parse(table.Range.XML);

                CellInfo[,] cellInfos = GetInitializedArray(table);

                var xmlTable = doc.Descendants().First(n => n.Name.LocalName == "tbl");

                var rows = xmlTable.Elements().Where(e => e.Name.LocalName == "tr").ToArray();

                for (int r = 0; r < rows.Length; r++)
                {
                    var row = rows[r];
                    var rowCells = row.Elements().Where(e => e.Name.LocalName == "tc").ToArray();
                    var c = 0;
                    foreach (var rowCell in rowCells)
                    {
                        cellInfos[r, c].XmlCell = rowCell;
                        cellInfos[r, c].XmlRow = r;
                        cellInfos[r, c].XmlColumn = c;

                        var gridSpan = int.Parse(rowCell.Descendants().FirstOrDefault(d => d.Name.LocalName == "gridSpan")?.Attributes().FirstOrDefault(a => a.Name.LocalName == "val")?.Value ?? "1");

                        if (gridSpan > 1)
                        {
                            for (int i = 1; i < gridSpan; i++)
                            {
                                cellInfos[r, c + i].MergedHorizontallyWith = rowCell;
                                cellInfos[r, c + i].XmlRow = r;
                                cellInfos[r, c + i].XmlColumn = c + i;
                            }

                        }

                        c += gridSpan;
                    }
                }

                ApplyVerticalMerges(cellInfos);

                FindCorrespondingInteropCells(table, cellInfos);

                return cellInfos;
            }


            private static CellInfo[,] GetInitializedArray(Word.Table table)
            {
                var cellInfos = new CellInfo[table.Rows.Count, table.Columns.Count];
                for (int r = 0; r < cellInfos.GetLength(0); r++)
                {
                    for (int c = 0; c < cellInfos.GetLength(1); c++)
                    {
                        cellInfos[r, c] = new CellInfo();
                    }
                }

                return cellInfos;
            }

            private static void ApplyVerticalMerges(CellInfo[,] cellInfos)
            {
                for (int r = 0; r < cellInfos.GetLength(0); r++)
                {
                    for (int c = 0; c < cellInfos.GetLength(1); c++)
                    {
                        var cellInfo = cellInfos[r, c];


                        var vmerge = cellInfo.XmlCell?.Descendants().FirstOrDefault(d => d.Name.LocalName == "vmerge");
                        if (vmerge != null)
                        {
                            var isParent = (vmerge.Attributes().FirstOrDefault(a => a.Name.LocalName == "val")?.Value ?? string.Empty) == "restart";

                            if (isParent)
                            {
                                MarkCellsBelow(cellInfos, r, c);
                            }
                        }

                    }
                }
            }

            private static void MarkCellsBelow(CellInfo[,] cells, int parentR, int parentC)
            {
                var parentCell = cells[parentR, parentC];
                for (int r = parentR + 1; r < cells.GetLength(1); r++)
                {
                    var cell = cells[r, parentC];

                    var vmerge = cell.XmlCell?.Descendants().FirstOrDefault(d => d.Name.LocalName == "vmerge");
                    if (vmerge == null) break;

                    var isParent = (vmerge?.Attributes().FirstOrDefault(a => a.Name.LocalName == "val")?.Value ?? string.Empty) == "restart";
                    if (isParent) break;

                    cell.MergedVerticallyWith = parentCell.XmlCell;
                }

            }

            private static void FindCorrespondingInteropCells(Word.Table table, CellInfo[,] cellInfos)
            {
                var interopRow = 1;
                for (int r = 0; r < cellInfos.GetLength(0); r++)
                {
                    var interopCol = 0;
                    for (int c = 0; c < cellInfos.GetLength(1); c++)
                    {
                        var cellInfo = cellInfos[r, c];

                        if (cellInfo.MergedVerticallyWith != null)
                        {
                            interopCol++;
                        }

                        else
                        {
                            interopCol++;
                            cellInfo.Row = interopRow;
                            cellInfo.Column = interopCol;
                            cellInfo.Cell = GetCell(cellInfo, table);
                        }
                    }

                    interopRow++;
                }
            }

            private static Word.Cell GetCell(CellInfo cellInfo, Word.Table table)
            {
                foreach (var cell in table.Range.Cells)
                {
                    if (cell.NestingLevel == table.NestingLevel)
                    {
                        if (cellInfo.Column == cell.ColumnIndex && cellInfo.Row == cell.RowIndex)
                        {
                            return cell;
                        }
                    }
                }

                return null;
            }

        }

    }
}

如果只想知道一个表是否完全包含合并的单元格,则可以使用Table.Uniform属性.

If you only want to know whether a table contains merged cells at all, you can use the Table.Uniform property.

这篇关于如何识别单词表中合并的行和列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆