为什么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两个工作表,我得到的数据是有数据行的两倍。 为什么是这个,它实际上是什么意思? 这是否意味着OpenXMLparsing每个列表两次?

编辑

那么,我find了一个解决scheme。 为了马上得到它,我想,你应该把这个神圣的知识保存在一个秘密的地方。 所以,这里是:

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

你得到两倍数的原因是由于OpenXmlReader读取每个元素的方式。 阅读器将打开和closures的节点视为可以通过检查IsStartElementIsEndElement属性来区分的独立项目。

为了certificate这一点,你可以运行这样的东西:

 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"); } } } 

这将产生沿着下面的行输出*为两行两列的表(我已经突出了行的可读性):

行真假
细胞真假
CellValue True False
CellValue假真
单元格错误
细胞真假
CellValue True False
CellValue假真
单元格错误
排假是真的
行真假
细胞真假
CellValue True False
CellValue假真
单元格错误
细胞真假
CellValue True False
CellValue假真
单元格错误
排假是真的

有两种方法可以解决这个问题,这取决于你如何阅读文档。 第一种方法(就像你在答案中指出的那样)是通过调用ReadNextSibling移动到下一个兄弟ReadNextSibling – 这实质上是“跳转”了终止元素(以及Row任何子节点)。 更改上面的示例以在do循环中使用ReadNextSibling

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

你会得到输出*的:

行真假
行真假

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

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

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

*实际上,每行都以“DocumentFormat.OpenXml.Spreadsheet”的名称空间作为前缀。 我已经删除了可读性。

这按预期工作:

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