我像这样计算两个工作表中的行数:
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_first
和 count_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
的所有子元素)。将上面的示例更改为使用 ReadNextSibling
在do
循环:
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/