Skip to content

Commit 68d1f81

Browse files
authored
Merge pull request #35 from ncdcdev/fix/excel-merged-cells
fix: JSON出力に結合セル情報を含める
2 parents 2578a33 + 1f49e4e commit 68d1f81

13 files changed

Lines changed: 1112 additions & 767 deletions

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ Two authentication methods are supported:
3535
- Read or search Excel files in SharePoint
3636
- Search mode: find cells containing specific text with `query` parameter
3737
- Read mode: get data from specific sheets/ranges with `sheet` and `cell_range` parameters
38-
- Auto-include headers: with `include_header` parameter, automatically includes frozen rows (detected via `freeze_panes`) as headers even when they're outside the specified cell range
39-
- Metadata-only mode: exclude data rows and retrieve only headers and file structure with `metadata_only` parameter
40-
- Default: lightweight response with value and coordinate only
41-
- Optional: include formatting (data_type, fill colors, merged cells, dimensions)
38+
- Response includes data in `rows` and structure info (`freeze_panes`, `merged_ranges`) when available
39+
- Default: value + coordinate (structural info such as merged ranges is included when present)
40+
- Optional: include_formatting currently does not change the output; structural info is still included only when present
4241
- No Excel Services dependency - uses direct file download + openpyxl parsing
4342

4443
### OneDrive Support

README_ja.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ stdioとHTTPの両方のトランスポートに対応しています。
3535
- SharePoint上のExcelファイルの読み取りと検索
3636
- 検索モード: `query`パラメータで特定テキストを含むセルを検索
3737
- 読み取りモード: `sheet``cell_range`パラメータで特定シート/範囲を取得
38-
- ヘッダー自動追加: `include_header`パラメータで`freeze_panes`で固定された行をヘッダーとして認識し、範囲指定時にヘッダーが範囲外でも自動的に追加
39-
- メタデータのみ取得: `metadata_only`パラメータでデータ行を除外し、ヘッダーとファイル構造のみ取得
40-
- デフォルト: 値と座標のみの軽量レスポンス
41-
- オプション: 書式情報を含む(データ型、塗りつぶし色、結合セル、サイズ)
38+
- 構造情報(`freeze_panes`)とデータを `rows` で常に返却し、結合セルがある場合は `merged_ranges` も含めて返却
39+
- デフォルト: 値と座標のみ(結合セルがある場合は merged / merged_ranges を追加)
40+
- オプション: include_formatting を指定しても返却内容(値・座標・結合セル情報など)は変わらない(結合セル情報は結合セルが存在する場合にのみ付与)
4241
- Excel Services不要 - 直接ファイルダウンロード+openpyxl解析方式
4342

4443
### OneDrive対応

docs/usage.md

Lines changed: 76 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,28 @@ SHAREPOINT_ONEDRIVE_PATHS=sales1@company.com:/Documents/Customers,sales2@company
166166
SHAREPOINT_SITE_NAME=@onedrive,sales-team,customer-portal
167167
```
168168

169+
### `sharepoint_docs_search` Parameters
170+
171+
| Parameter | Type | Default | Description |
172+
|-----------|------|---------|-------------|
173+
| `query` | str | Required | Search keyword |
174+
| `max_results` | int | 20 | Max results (capped at 100) |
175+
| `file_extensions` | list[str] \| None | None | File extensions filter (unsupported values are ignored) |
176+
| `response_format` | str | `detailed` | `detailed` or `compact` |
177+
178+
- `max_results` is capped at 100.
179+
- `file_extensions` is filtered by `SHAREPOINT_ALLOWED_FILE_EXTENSIONS`; unsupported values are ignored.
180+
- `response_format="compact"` returns only `title` / `path` / `extension` to reduce tokens.
181+
182+
**Compact response example**
183+
```python
184+
results = sharepoint_docs_search(
185+
query="budget 2024",
186+
response_format="compact",
187+
max_results=10,
188+
)
189+
```
190+
169191
## Excel Operations Usage Examples
170192

171193
The `sharepoint_excel` tool allows you to read and search Excel files in SharePoint. It supports two modes:
@@ -186,9 +208,7 @@ The `sharepoint_excel` tool allows you to read and search Excel files in SharePo
186208
| `query` | str \| None | None | Search keyword (enables search mode) |
187209
| `sheet` | str \| None | None | Sheet name (get specific sheet only) |
188210
| `cell_range` | str \| None | None | Cell range (e.g., "A1:D10") |
189-
| `include_formatting` | bool | False | Include formatting information |
190-
| `include_header` | bool | True | Auto-detect and separate header rows using `freeze_panes` |
191-
| `metadata_only` | bool | False | Exclude data rows to return only metadata (reduce response size) |
211+
| `include_formatting` | bool | False | Does not change the output currently (merged info is always included when present) |
192212

193213
### Basic Workflow
194214

@@ -256,102 +276,18 @@ result = sharepoint_excel(
256276
)
257277
```
258278

259-
#### 5. Read with Formatting Information
279+
#### 5. include_formatting flag (no output changes yet)
260280
```python
261-
# Get data with formatting (colors, merged cells, etc.)
281+
# include_formatting flag (currently does not change output)
262282
result = sharepoint_excel(
263283
file_path="/sites/finance/Shared Documents/report.xlsx",
264284
sheet="Sheet1",
265285
include_formatting=True
266286
)
267287
```
268288

269-
#### 6. Automatic Header Detection
270-
```python
271-
# Auto-detect and separate header and data rows using freeze_panes
272-
result = sharepoint_excel(
273-
file_path="/sites/finance/Shared Documents/report.xlsx",
274-
sheet="Sheet1",
275-
include_header=True
276-
)
277-
```
278-
279-
**Header Detection Response:**
280-
```json
281-
{
282-
"file_path": "/sites/finance/Shared Documents/report.xlsx",
283-
"sheets": [{
284-
"name": "Sheet1",
285-
"freeze_panes": "B2",
286-
"frozen_rows": 1,
287-
"frozen_cols": 1,
288-
"header_rows": [
289-
[
290-
{"value": "Product", "coordinate": "A1"},
291-
{"value": "Price", "coordinate": "B1"},
292-
{"value": "Stock", "coordinate": "C1"}
293-
]
294-
],
295-
"data_rows": [
296-
[
297-
{"value": "Product A", "coordinate": "A2"},
298-
{"value": 1000, "coordinate": "B2"},
299-
{"value": 50, "coordinate": "C2"}
300-
],
301-
...
302-
]
303-
}]
304-
}
305-
```
306-
307-
**Features:**
308-
- Auto-detects Excel freeze panes (frozen rows/columns)
309-
- Separates header rows and data rows in response (default behavior)
310-
- When `cell_range` is specified, automatically includes frozen range
311-
- Set `include_header=False` to return legacy `rows` format
312-
```
313-
314-
#### 7. Metadata-Only Mode (File Structure Inspection)
315-
```python
316-
# Get only file structure without data rows
317-
result = sharepoint_excel(
318-
file_path="/sites/finance/Shared Documents/large-report.xlsx",
319-
metadata_only=True
320-
)
321-
```
322-
323-
**Metadata-Only Response:**
324-
```json
325-
{
326-
"file_path": "/sites/finance/Shared Documents/large-report.xlsx",
327-
"sheets": [{
328-
"name": "Sheet1",
329-
"freeze_panes": "B2",
330-
"frozen_rows": 1,
331-
"frozen_cols": 1,
332-
"dimensions": "A1:E1000",
333-
"header_rows": [
334-
[
335-
{"value": "Product", "coordinate": "A1"},
336-
{"value": "Price", "coordinate": "B1"},
337-
{"value": "Stock", "coordinate": "C1"}
338-
]
339-
],
340-
"data_rows": []
341-
}]
342-
}
343-
```
344-
345-
**Use Cases:**
346-
- Inspect large file structure before fetching data
347-
- Understand what headers exist in each sheet
348-
- Determine the necessary `cell_range` before retrieving full data
349-
- Significantly reduce response size (save tokens)
350-
351-
**Recommended Workflow:**
352-
1. Use `metadata_only=True` to inspect file structure
353-
2. Identify the required range
354-
3. Fetch actual data with specific `cell_range`
289+
Note: `include_formatting=true` currently does not return colors/width/height/types.
290+
Merged cell info (`merged` / `merged_ranges`) is always included when present.
355291

356292
### JSON Output Format
357293

@@ -400,7 +336,10 @@ result = sharepoint_excel(
400336
}
401337
```
402338

403-
#### With Formatting (include_formatting=true)
339+
#### Formatting (include_formatting behavior)
340+
341+
In the current implementation, `include_formatting=true` does not change the output.
342+
Merged cell info (`merged` / `merged_ranges`) is included regardless of `include_formatting`.
404343

405344
```json
406345
{
@@ -414,20 +353,21 @@ result = sharepoint_excel(
414353
{
415354
"value": "Department",
416355
"coordinate": "A1",
417-
"data_type": "s",
418-
"fill": {
419-
"pattern_type": "solid",
420-
"fg_color": "#CCCCCC",
421-
"bg_color": null
422-
},
423356
"merged": {
424357
"range": "A1:B1",
425358
"is_top_left": true
426-
},
427-
"width": 15.0,
428-
"height": 20.0
359+
}
429360
}
430361
]
362+
],
363+
"merged_ranges": [
364+
{
365+
"range": "A1:B1",
366+
"anchor": {
367+
"coordinate": "A1",
368+
"value": "Department"
369+
}
370+
}
431371
]
432372
}
433373
]
@@ -440,12 +380,35 @@ result = sharepoint_excel(
440380
- **value**: Cell value (string, number, date, formula, etc.)
441381
- **coordinate**: Cell position (e.g., "A1", "B2")
442382

443-
**With include_formatting=true:**
444-
- **data_type**: Data type code (`s`=string, `n`=number, `f`=formula, etc.)
445-
- **fill**: Fill color information (pattern type, foreground/background colors)
383+
**When merged cells exist (included regardless of include_formatting):**
446384
- **merged**: Merged cell information (range, position)
447-
- **width**: Column width
448-
- **height**: Row height
385+
- **merged_ranges**: Merged ranges list per sheet (range + anchor info)
386+
387+
Note: `include_formatting` currently does not add formatting fields.
388+
389+
### Additional Metadata
390+
391+
Depending on the request, the response can include metadata such as `response_kind`, `data_included`, `requested_sheet`, `requested_range`, `freeze_panes`, `frozen_rows`, `frozen_cols`, `effective_range`, `sheet_resolution`, and `available_sheets`.
392+
393+
### Sheet Resolution and Fallbacks
394+
395+
- `sheet` is resolved by exact match or a unique `trim + casefold` match.
396+
- If not resolved, `sheet_resolution` and `available_sheets` are returned with a `warning`.
397+
- If `cell_range` is provided and `sheet` is not found, the parser falls back to all sheets.
398+
- If `sheet` is not found and no `cell_range` is provided, `sheets` is empty and `candidates` are returned.
399+
400+
### Cell Range Normalization and Expansion
401+
402+
`cell_range` is normalized/expanded internally, and the result is returned as `effective_range`.
403+
404+
- Column-only ranges (e.g., `J` / `J:J`) expand to `J1:J<max_row>`.
405+
- Single cell ranges (e.g., `C5`) expand to `C1:C5`.
406+
- Single-row ranges (e.g., `D5:H5`) expand to `A5:H5`.
407+
408+
### Large Range Limits
409+
410+
If rows/cols exceed limits, a `ValueError` is raised.
411+
Use `cell_range` to narrow the selection.
449412

450413
### Common Use Cases
451414

@@ -463,18 +426,17 @@ search_result = sharepoint_excel(file_path=file_path, query="Total Revenue")
463426
data = sharepoint_excel(file_path=file_path, sheet="Sheet1", cell_range="A1:D20")
464427
```
465428

466-
**Analyze Cell Formatting**
429+
**Inspect Merged Cells**
467430
```python
468-
# Get Excel data with formatting
469-
json_data = sharepoint_excel(file_path=file_path, include_formatting=True)
431+
# Get Excel data (merged info is included when present)
432+
json_data = sharepoint_excel(file_path=file_path)
470433
data = json.loads(json_data)
471434

472-
# Find cells with specific formatting
435+
# List merged ranges
473436
for sheet in data["sheets"]:
474-
for row in sheet["rows"]:
475-
for cell in row:
476-
if cell.get("fill", {}).get("fg_color"):
477-
print(f"Colored cell at {cell['coordinate']}: {cell['value']}")
437+
for merged in sheet.get("merged_ranges", []):
438+
anchor = merged.get("anchor", {})
439+
print(f"Merged range {merged['range']}: {anchor.get('value')}")
478440
```
479441

480442
**Export Specific Sheet to CSV**

0 commit comments

Comments
 (0)