Электронная таблица очень сложна, поэтому, если вам нужна дополнительная помощь, вы можете предоставить более подробную информацию.
Вам нужно:
- Лучший способ для анализа электронных таблиц как таковых, чтобы XML
- Каково ваше состояние?
- Excel означает Microsoft-Office, Google-Spreadsheet или?
- какую версию Excel вы можете принять?
- Что делать, если Excel содержит сценарий? (VBA ...)
- Что делать, если ячейка содержит формулу?
- Что делать, если блокировка (или защита)?
- Нужно ли вам напишите что-нибудь в Excel. (вероятно, нет)
- Тебя волнует производительность или нет? (COM)
- Вы хотите обработать конкретный текст (например, _x0020_, ...) ...
Я имею в виду, если вы хотите поговорить о лучшем , пожалуйста, поставьте это условие. В противном случае это относится к личному виду.
Я даю вам ссылку , чтобы вы могли увидеть, какая библиотека может быть вам полезна
Я все же приведу вам пример (я предполагаю, что случай максимально простой), как показано ниже,
тестовые данные
test_data.xlsx
you can get it from this ссылка
код
from openpyxl import load_workbook
from xml.dom import minidom
from xml.etree.ElementTree import tostring
from xml.etree.ElementTree import Element, ElementTree
from openpyxl.worksheet.merge import MergedCellRange
from openpyxl.worksheet.dimensions import SheetFormatProperties
from openpyxl.worksheet.worksheet import Worksheet
from openpyxl.workbook.workbook import Workbook
from openpyxl.cell.cell import Cell
from typing import Tuple, List, Union
def prettify(elem: Element):
"""
https://pymotw.com/2/xml/etree/ElementTree/create.html
"""
rough_string = tostring(elem, 'utf-8')
re_parsed = minidom.parseString(rough_string)
return re_parsed.toprettyxml(indent=' ') # 4 space
TABLE_START_ROW = 10
def main():
wb: Workbook = load_workbook('test_data.xlsx')
root = Element('root')
table = Element('table')
tbody = Element('tbody')
for sheet in [wb[sheet_name] for sheet_name in wb.sheetnames]:
# print(sheet.title)
sheet: Worksheet
sheet_prop: SheetFormatProperties = sheet.sheet_format
default_width = sheet_prop.baseColWidth
default_height = sheet_prop.defaultRowHeight
merge_cell_list: MergedCellRange = sheet.merged_cells.ranges
for row in sheet.rows:
if not any([cell.value for cell in row]):
root.append(Element('p')) # empty line
continue
cur_row = row[0].row
if cur_row < TABLE_START_ROW:
# `NOT TABLE` DATA
data_list = []
for cell in row:
cell: Cell
if cell.value:
merge_info: List[Union[None, MergedCellRange]] = [
merge_cell for merge_cell in filter(lambda merge_cell: cell.coordinate in merge_cell,
merge_cell_list)
]
is_merge = len(merge_info) > 0
if is_merge:
# It should recalculate the width and height.
merge_range: MergedCellRange = merge_info[0]
size: dict = merge_range.size
num_col = size['columns']
num_row = size['rows']
width = 0
for idx in range(num_col):
width += sheet.column_dimensions[
chr(ord(cell.column_letter)+idx) # A B ...
].width
height = 0
for idx in range(num_row):
new_height = sheet.row_dimensions[cell.row+idx].height
height += new_height if new_height else default_height
else:
width = sheet.column_dimensions[cell.column_letter].width
height = sheet.row_dimensions[cell.row].height
height = default_height if height is None else height
merge_info: Union[Tuple[bool, str], List[None]] = \
(is_merge, merge_info[0].coord) if merge_info else [None]
align: Tuple[str, str] = (cell.alignment.horizontal, cell.alignment.vertical)
data_list.append((str(cell.value), align, (height, width), merge_info))
p_list = [] # for the `div` tag
for value, (text_align, vertical_align), (h, w), merge_info in data_list:
is_merge, *coord = merge_info
p = Element('p')
p.text = value
if text_align:
p.attrib['text_align'] = text_align
# show w and h only on align cells
p.attrib['width'] = str(w)
p.attrib['height'] = str(h)
if vertical_align:
p.attrib['vertical_align'] = vertical_align
if is_merge:
p.attrib['merge_coord'] = coord[0]
p_list.append(p)
if len(data_list) > 1:
div = Element('div')
for tag_p in p_list:
div.append(tag_p)
root.append(div)
else:
root.append(p_list[0])
elif cur_row == TABLE_START_ROW:
# TABLE HEADER
thead = Element('thead')
tr = Element('tr')
thead.append(tr)
for cell in row:
th = Element('th')
th.text = str(cell.value)
tr.append(th)
table.append(thead)
table.append(tbody)
root.append(table)
else:
# TABLE ROW
tr = Element('tr')
for cell in row:
td = Element('td')
td.text = f'{cell.value:0,.0f}' if isinstance(cell.value, int) else str(cell.value)
tr.append(td)
tbody.append(tr)
if not 'output mode is compressed':
tree = ElementTree(root)
tree.write('result_compressed.xml') # ugly (The output format compressed that is not easy for human reading.)
return
with open('result.xml', 'w', encoding='utf-8') as f:
f.write(prettify(root))
if __name__ == '__main__':
main()
Тест в Excel 2013 (v15.0) | Python 3.7.3 | openpyxl 3.0.4
demo
<?xml version="1.0" ?>
<root>
<p>1.Title for Sheet1</p>
<p/>
<div>
<p>Paragraph for Sheet1</p>
<p>p1.sub.msg</p>
</div>
<p/>
<p height="47.25" merge_coord="A5:B6" text_align="center" width="53.0">Paragraph2 for Sheet1 (merge)</p>
<p/>
<p/>
<p height="36.75" text_align="right" vertical_align="center" width="33.0">align_right_vertical_center</p>
<p/>
<table>
<thead>
<tr>
<th>Content</th>
<th>2019</th>
<th>2020</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>2,500</td>
<td>3,500</td>
</tr>
<tr>
<td>B</td>
<td>4,500</td>
<td>6,000</td>
</tr>
</tbody>
</table>
</root>
Я добавляю div
намеренно. Это означает, что они находятся в одном ряду.