@@ -107,6 +107,7 @@ def parse_to_json(
107107 sheet_name : str | None = None ,
108108 cell_range : str | None = None ,
109109 include_frozen_rows : bool = True ,
110+ include_cell_styles : bool = False ,
110111 ) -> str :
111112 """
112113 Excelファイルを解析してJSON形式で返す
@@ -118,13 +119,16 @@ def parse_to_json(
118119 include_frozen_rows: cell_range指定時に固定行(ヘッダー)を自動追加
119120 True(デフォルト): frozen_rowsで指定された行を自動的に取得
120121 False: 指定されたcell_rangeのみを取得
122+ include_cell_styles: セルの色・サイズ情報(default: false)
123+ 色分けデータ抽出時のみ使用。トークン消費+約20%
121124
122125 Returns:
123126 JSON文字列
124127 - 各セルのデータ: value(値)、coordinate(座標)
125128 - 構造情報: シート名、dimensions(シート全体のセル範囲、例: "A1:D10")
126129 - 構造情報: frozen_rows(固定行数)、frozen_cols(固定列数)
127130 - 条件付き構造情報: freeze_panes(存在する場合)、merged_ranges(結合セルが存在する場合)
131+ - スタイル情報(include_cell_styles=Trueの場合): fill(背景色)、width(列幅)、height(行高さ)
128132 """
129133 logger .info (
130134 f"Parsing Excel file: { file_path } (sheet={ sheet_name } , range={ cell_range } )"
@@ -205,6 +209,7 @@ def parse_to_json(
205209 sheet ,
206210 cell_range ,
207211 include_frozen_rows ,
212+ include_cell_styles ,
208213 )
209214 result ["sheets" ].append (sheet_data )
210215
@@ -289,9 +294,7 @@ def _scan_sheet(
289294 }
290295 )
291296
292- def _calculate_header_range (
293- self , cell_range : str , frozen_rows : int
294- ) -> str | None :
297+ def _calculate_header_range (self , cell_range : str , frozen_rows : int ) -> str | None :
295298 """
296299 セル範囲に対してfrozen_rowsに基づくヘッダー範囲を計算
297300
@@ -393,6 +396,7 @@ def _parse_sheet(
393396 sheet ,
394397 cell_range : str | None = None ,
395398 include_frozen_rows : bool = True ,
399+ include_cell_styles : bool = False ,
396400 ) -> dict [str , Any ]:
397401 """
398402 シートを解析してdict形式で返す
@@ -401,6 +405,7 @@ def _parse_sheet(
401405 sheet: openpyxl Worksheet
402406 cell_range: セル範囲指定(例: "A1:D10")
403407 include_frozen_rows: cell_range指定時に固定行(ヘッダー)を自動追加
408+ include_cell_styles: セルのスタイル情報を含めるか
404409
405410 Returns:
406411 シートデータのdict
@@ -467,7 +472,9 @@ def _parse_sheet(
467472
468473 # ヘッダー自動追加の場合、マージセルキャッシュにもヘッダー範囲を含める
469474 if include_frozen_rows and frozen_rows > 0 :
470- header_range = self ._calculate_header_range (effective_range , frozen_rows )
475+ header_range = self ._calculate_header_range (
476+ effective_range , frozen_rows
477+ )
471478 if header_range :
472479 # ヘッダー範囲とデータ範囲を結合した範囲を計算
473480 effective_range_for_merge = self ._merge_ranges (
@@ -530,6 +537,7 @@ def _parse_sheet(
530537 all_rows .extend (
531538 self ._parse_rows (
532539 header_rows ,
540+ include_cell_styles ,
533541 merged_cell_map ,
534542 merged_anchor_value_map ,
535543 )
@@ -541,6 +549,7 @@ def _parse_sheet(
541549 all_rows .extend (
542550 self ._parse_rows (
543551 rows_to_process ,
552+ include_cell_styles ,
544553 merged_cell_map ,
545554 merged_anchor_value_map ,
546555 )
@@ -554,6 +563,7 @@ def _parse_sheet(
554563 all_rows .extend (
555564 self ._parse_rows (
556565 rows_to_process ,
566+ include_cell_styles ,
557567 merged_cell_map ,
558568 merged_anchor_value_map ,
559569 )
@@ -741,6 +751,7 @@ def _expand_axis_range(self, range_str: str) -> str:
741751 def _parse_cell (
742752 self ,
743753 cell ,
754+ include_cell_styles : bool = False ,
744755 merged_cell_map : dict [str , str ] | None = None ,
745756 merged_anchor_value_map : dict [str , Any ] | None = None ,
746757 ) -> dict [str , Any ]:
@@ -749,6 +760,7 @@ def _parse_cell(
749760
750761 Args:
751762 cell: openpyxl Cell
763+ include_cell_styles: セルのスタイル情報を含めるか(デフォルト: False)
752764 merged_cell_map: マージセル座標からマージ範囲へのマップ(パフォーマンス最適化用)
753765 merged_anchor_value_map: マージ範囲 -> アンカー値 のマップ(結合セルの値埋め用)
754766
@@ -776,12 +788,43 @@ def _parse_cell(
776788 if anchor_value is not None :
777789 cell_data ["value" ] = anchor_value
778790
779- # 書式情報(fill/width/height/data_type)は現在サポートされていません
791+ # スタイル情報(include_cell_styles=Trueの場合のみ)
792+ if include_cell_styles :
793+ # 背景色情報
794+ if cell .fill and cell .fill .patternType :
795+ fill_info = {
796+ "pattern_type" : cell .fill .patternType ,
797+ }
798+ fg_color = self ._color_to_hex (cell .fill .fgColor )
799+ if fg_color :
800+ fill_info ["fg_color" ] = fg_color
801+ bg_color = self ._color_to_hex (cell .fill .bgColor )
802+ if bg_color :
803+ fill_info ["bg_color" ] = bg_color
804+ cell_data ["fill" ] = fill_info
805+
806+ # セルサイズ(列幅・行高さ)
807+ # MergedCellの場合は属性が存在しないため、hasattrでチェック
808+ if hasattr (cell , "column_letter" ) and hasattr (cell , "row" ):
809+ if cell .column_letter and cell .row :
810+ sheet = cell .parent
811+ # 列幅
812+ if cell .column_letter in sheet .column_dimensions :
813+ col_dim = sheet .column_dimensions [cell .column_letter ]
814+ if col_dim .width :
815+ cell_data ["width" ] = col_dim .width
816+ # 行高さ
817+ if cell .row in sheet .row_dimensions :
818+ row_dim = sheet .row_dimensions [cell .row ]
819+ if row_dim .height :
820+ cell_data ["height" ] = row_dim .height
821+
780822 return cell_data
781823
782824 def _parse_rows (
783825 self ,
784826 rows : tuple [tuple [Cell , ...], ...],
827+ include_cell_styles : bool = False ,
785828 merged_cell_map : dict [str , str ] | None = None ,
786829 merged_anchor_value_map : dict [str , Any ] | None = None ,
787830 ) -> list [list [dict [str , Any ]]]:
@@ -790,6 +833,7 @@ def _parse_rows(
790833
791834 Args:
792835 rows: 行データのタプル
836+ include_cell_styles: セルのスタイル情報を含めるか
793837 merged_cell_map: マージセル情報
794838 merged_anchor_value_map: マージ範囲 -> アンカー値
795839
@@ -801,6 +845,7 @@ def _parse_rows(
801845 row_data = [
802846 self ._parse_cell (
803847 cell ,
848+ include_cell_styles ,
804849 merged_cell_map ,
805850 merged_anchor_value_map ,
806851 )
0 commit comments