c# - 为什么 OpenXML 读取行两次

标签 c# excel openxml

我像这样计算两个工作表中的行数:

foreach (WorksheetPart worksheetPart in workbookPart.WorksheetParts)
{
    OpenXmlPartReader reader = new OpenXmlPartReader(worksheetPart);
    if (count == 0)
    {
        while (reader.Read())
        {
            if (reader.ElementType == typeof(Row))
            {
                count_first++;
            }
        }
    }
    else if (count == 1)
    {
        while (reader.Read())
        {
            if (reader.ElementType == typeof(Row))
            {
                count_second++;
            }
        }
    }
    count++;
}

对于 count_firstcount_second 中的两个工作表,我得到的数据是行数的两倍。为什么会这样,它究竟意味着什么?这是否意味着 OpenXML 将每个列表解析两次?

编辑

好吧,我找到了解决办法。为了马上得到它,我想,你应该把这个神圣的知识保存在某个 secret 的地方。所以,这里是:

while (reader.Read())
{
    if (reader.ElementType == typeof(Row))
    {
        do
        {
            count_first++;
        }   while (reader.ReadNextSibling());
    }
}

最佳答案

您得到两倍计数的原因是 OpenXmlReader 的方式读取每个元素。读者将打开和关闭节点视为独立的项目,可以通过检查 IsStartElement 来区分它们。和 IsEndElement 属性。

为了演示这一点,您可以运行如下代码:

using (OpenXmlReader reader = OpenXmlReader.Create(worksheetPart))
{
    while (reader.Read())
    {
        if (reader.ElementType == typeof(Row))
        {
            do
            {
                Console.WriteLine("{0} {1} {2}", 
                                  reader.ElementType,
                                  reader.IsStartElement,
                                  reader.IsEndElement);
            } while (reader.Read());

            Console.WriteLine("Finished");
        }
    }
}

对于具有两行和两列的工作表,这将按照以下行*生成输出(为了便于阅读,我突出显示了行):

Row True False
Cell True False
CellValue True False
CellValue False True
Cell False True
Cell True False
CellValue True False
CellValue False True
Cell False True
Row False True
Row True False
Cell True False
CellValue True False
CellValue False True
Cell False True
Cell True False
CellValue True False
CellValue False True
Cell False True
Row False True

有两种方法可以解决这个问题,具体取决于您阅读文档的方式。第一种方法(正如您在回答中指出的那样)是通过调用 ReadNextSibling 移动到下一个 sibling 。 - 这实质上是“跳转”结束元素(以及 Row 的所有子元素)。将上面的示例更改为使用 ReadNextSiblingdo循环:

do
{
    Console.WriteLine("{0} {1} {2}", 
                       reader.ElementType,
                       reader.IsStartElement,
                       reader.IsEndElement);
} while (reader.ReadNextSibling());

您将获得以下输出*:

Row True False
Row True False

第二种方法是只计算开始元素(或者实际上是结束元素;只是不是两者):

while (reader.Read())
{
    if (reader.ElementType == typeof(Row) && reader.IsStartElement)
    {
        count_first++;
    }
}

你选择哪一个取决于你是否想阅读 Cell值以及您希望如何阅读它们(SAX 或 DOM)。

* 实际上,每一行都以“DocumentFormat.OpenXml.Spreadsheet”的命名空间为前缀。为了便于阅读,我已将其删除。

关于c# - 为什么 OpenXML 读取行两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28900251/

相关文章:

vba - 创建 Excel 宏以一次删除多行

email - 使用 OpenXML 在内存中发送电子邮件附件

xml - Excel 2003 XML 格式 - AutoFitWidth 不工作

c# - 从 CodeAttribute 中的参数获取 CodeClass?

JavaScript - 将 CSV 转换为 XLSX(最好不使用库)

vba - AdvancedFilter 宏在 AutoFilter 关闭时运行速度较慢

sql-server - 如何在 T-SQL 中从 XML 读取选项?

c# - 动态加载 DLL 中的接口(interface)

c# - 如何在没有第三方库的情况下序列化对象+压缩然后解压+反序列化?

c# - aws Lambda 函数中的 Webresponse c#