打开pyxl。忽略具有样式但没有值的单元格
Openpyxl. Ignoring cells that have style but have no values
我想知道有没有办法让 openpyxl 忽略没有值的单元格?单元格位于 xml 树中,但没有值,仅定义了样式
问题是,我有一个sheet,它的xml结构是这样的:
<row r="18" spans="3:9 16384:16384" ht="15" customHeight="1" thickBot="1">
<c r="C18" s="14" t="s">
<v>24</v>
</c>
<c r="D18" s="14" t="s">
<v>25</v>
</c>
<c r="E18" s="14" t="s">
<v>27</v>
</c>
...
<c r="I18" s="12"/>
<c r="XFD18" s="13"/>
</row>
<row r="1048576" spans="4:4" ht="15" customHeight="1">
<c r="D1048576" s="13"/>
</row>
当openpyxl
到达第18行并尝试获取单元格时,它生成单元格的方式使其用16336个空单元格填充单元格I18和XFD18之间的空隙。对于第 18 - 1048576 行也是如此,由于 XML 树中的行在 ws.iter_rows
方法中被解析的方式,我得到了一百万个空行。我看到了背后的逻辑,我知道这是 xlsx 文件本身的问题,但我想知道这是否是我可以使用 openpyxl API?
处理的问题
我知道 xlrd
会忽略空单元格格式(只是没有实现),因此 xlrd
不会将此类单元格添加到行中。有没有办法让 openpyxl 行为相同?查看源代码,除了为 ws.iter_rows
方法定义 max_column
和 max_row
之外,我看不到使用现有 API 的方法(这不是最佳的,因为实际数量columns/rows 可能会有所不同)
我设法完成了修改 xml_source
的任务(wb 打开为 read_only):
import io
import xml.etree.ElementTree as ET
from openpyxl.xml.functions import iterparse, safe_iterator
from openpyxl.xml.constants import SHEET_MAIN_NS
ROW_TAG = '{%s}row' % SHEET_MAIN_NS
CELL_TAG = '{%s}c' % SHEET_MAIN_NS
VALUE_TAG = '{%s}v' % SHEET_MAIN_NS
SHEET_DATA = '{%s}sheetData' % SHEET_MAIN_NS
def clean_up_xml_from_empty_rows_and_cells(sheet):
sheet_data = None
rows_to_delete = set()
p = iterparse(sheet.xml_source, tag=[ROW_TAG], remove_blank_text=True)
for _event, element in p:
if element.tag == SHEET_DATA:
sheet_data = element
continue
if element.tag == ROW_TAG:
cells_to_delete = set()
for cell in safe_iterator(element, CELL_TAG):
if cell.findtext(VALUE_TAG) is None:
cells_to_delete.add(cell)
for cell in cells_to_delete:
element.remove(cell)
if not len(element):
rows_to_delete.add(element)
for row in rows_to_delete:
sheet_data.remove(row)
out_file = io.BytesIO()
element_tree = ET.ElementTree(p.root)
element_tree.write(out_file, encoding='utf8')
out_file.seek(0)
sheet.xml_source = out_file
可是感觉好不对啊!如此危险,我绝对不确定这样的功能不会破坏其他 xlsx 文件的解析。
真的没有办法忽略没有值的单元格吗?浏览SO和google——感觉从来没有人遇到过这样的问题:(
你可能最好不要修补 parse_row()
,这是控制这些东西的地方。这比搞乱解析器更容易使用。
我想知道有没有办法让 openpyxl 忽略没有值的单元格?单元格位于 xml 树中,但没有值,仅定义了样式
问题是,我有一个sheet,它的xml结构是这样的:
<row r="18" spans="3:9 16384:16384" ht="15" customHeight="1" thickBot="1">
<c r="C18" s="14" t="s">
<v>24</v>
</c>
<c r="D18" s="14" t="s">
<v>25</v>
</c>
<c r="E18" s="14" t="s">
<v>27</v>
</c>
...
<c r="I18" s="12"/>
<c r="XFD18" s="13"/>
</row>
<row r="1048576" spans="4:4" ht="15" customHeight="1">
<c r="D1048576" s="13"/>
</row>
当openpyxl
到达第18行并尝试获取单元格时,它生成单元格的方式使其用16336个空单元格填充单元格I18和XFD18之间的空隙。对于第 18 - 1048576 行也是如此,由于 XML 树中的行在 ws.iter_rows
方法中被解析的方式,我得到了一百万个空行。我看到了背后的逻辑,我知道这是 xlsx 文件本身的问题,但我想知道这是否是我可以使用 openpyxl API?
我知道 xlrd
会忽略空单元格格式(只是没有实现),因此 xlrd
不会将此类单元格添加到行中。有没有办法让 openpyxl 行为相同?查看源代码,除了为 ws.iter_rows
方法定义 max_column
和 max_row
之外,我看不到使用现有 API 的方法(这不是最佳的,因为实际数量columns/rows 可能会有所不同)
我设法完成了修改 xml_source
的任务(wb 打开为 read_only):
import io
import xml.etree.ElementTree as ET
from openpyxl.xml.functions import iterparse, safe_iterator
from openpyxl.xml.constants import SHEET_MAIN_NS
ROW_TAG = '{%s}row' % SHEET_MAIN_NS
CELL_TAG = '{%s}c' % SHEET_MAIN_NS
VALUE_TAG = '{%s}v' % SHEET_MAIN_NS
SHEET_DATA = '{%s}sheetData' % SHEET_MAIN_NS
def clean_up_xml_from_empty_rows_and_cells(sheet):
sheet_data = None
rows_to_delete = set()
p = iterparse(sheet.xml_source, tag=[ROW_TAG], remove_blank_text=True)
for _event, element in p:
if element.tag == SHEET_DATA:
sheet_data = element
continue
if element.tag == ROW_TAG:
cells_to_delete = set()
for cell in safe_iterator(element, CELL_TAG):
if cell.findtext(VALUE_TAG) is None:
cells_to_delete.add(cell)
for cell in cells_to_delete:
element.remove(cell)
if not len(element):
rows_to_delete.add(element)
for row in rows_to_delete:
sheet_data.remove(row)
out_file = io.BytesIO()
element_tree = ET.ElementTree(p.root)
element_tree.write(out_file, encoding='utf8')
out_file.seek(0)
sheet.xml_source = out_file
可是感觉好不对啊!如此危险,我绝对不确定这样的功能不会破坏其他 xlsx 文件的解析。
真的没有办法忽略没有值的单元格吗?浏览SO和google——感觉从来没有人遇到过这样的问题:(
你可能最好不要修补 parse_row()
,这是控制这些东西的地方。这比搞乱解析器更容易使用。