ホーム / お役立ち記事 / Python で書き出した Excel が「修復」を求める理由|消えた名前空間の宣言と出す前の検査

Knowledge

Python で​書き出した​ Excel が​「修復」を​求める​理由|​消えた​名前​空間の​宣言と​出す前の​検査

Python で書き出した Excel を開くと「一部の内容に問題が見つかりました」と出て、修復を求められることがあります。弊社が切り分けた事例では、XML を ElementTree で読み書きして名前空間の宣言が落ち、互換性の属性だけが残っていました。openpyxl で読み直せても、Excel は修復を求めます。原因の切り分け、見分け方、宣言を補う直し方、落とし穴、出す前に通す検査を、弊社が実際の Excel で測った結果と ECMA-376 の仕様でまとめます。

著者: 村山 悠太(ゴムマリ) 最終更新: 2026年11月

Python で書き出した Excel ファイルを開くと、「一部の内容に問題が見つかりました。可能な限り内容を回復しますか?」と出て、修復を求められることがあります。

弊社が切り分けた事例では、原因は XML を Python の ElementTree で読み書きしたことでした。使っていない名前空間の宣言が落ち、その名前を挙げた互換性の属性だけが残っていました。

直し方は、書き出した XML に、落ちた宣言を補うことです。弊社が試した構成では、宣言を補った版は、2つの書き出し方とも Excel で修復を求められずに開きました(別のブックを作る方式の版は、calcChain.xml も外しています)。

この記事は、既存の Excel の様式に値を書き込む仕組みを作る・任されている業務の担当者・情報システムの担当者に向けて書きます。

原因の切り分け、見分け方、直し方、落とし穴、出す前に通す検査を、弊社が実際の Excel で測った結果と、ECMA-376(Office のファイルの形式の国際規格)の仕様で整理します。

原因: ​互換性の​属性が、​宣言の​無い​名前を​挙げている

.xlsx の中身は、ZIP にまとめた XML のファイル(パート)の束です。各パートの先頭には、新しい版の Excel が足した情報の名前空間が、x14ac のような短い名前(接頭辞)で宣言されています。

同じ先頭に、mc:Ignorable="x14ac xr" のような互換性の属性があります。「この接頭辞の情報は、読めなければ無視してよい」という印です。

ECMA-376 の Part 3(互換性と拡張)は、この属性に挙げる接頭辞ごとに、その要素から見える範囲で、接頭辞を結びつけた名前空間が無ければならない、と定めています(7.2 節)。

AlternateContent の中の mc:Choice Requires="x14" という属性も、同じ制約です(7.6 節・7.4 節)。

挙げた要素から見える範囲に宣言が無い接頭辞を使った例は、仕様の付録(参考)で「非適合」とされています(A.1.3)。

仕様は、処理系が非適合を見つけたら、それを利用側に知らせるべき(should)としています(9.1 節)。

非適合のパートを Excel がどう扱うかは、仕様には書かれていません。弊社の実測では、Excel はそのパートを捨てるか置き換えました。

ElementTree で​読み​書きすると、​使っていない​宣言だけが​落ちる

Python の標準の xml.etree.ElementTree で XML を読み、書き直すと、中で使われていない名前空間の宣言が出力から消えます。

属性の値は文字列なので、mc:Ignorable に並んだ接頭辞はそのまま残ります。

その結果、「宣言の無い接頭辞を互換性の属性に挙げた」XML ができます。弊社の調べ(2026年9月・Python 3.14)で、この形が修復の原因でした。

同じ動きは、短いコードで再現できます。次は、弊社が 2026年11月1日に Python 3.14.6 で流した結果です。

入力:  <styleSheet xmlns="…/main" xmlns:mc="…" mc:Ignorable="x14ac x16r2 xr"
         xmlns:x14ac="…" xmlns:x16r2="…" xmlns:xr="…"> …
出力:  <ns0:styleSheet xmlns:ns0="…/main" xmlns:ns1="…" ns1:Ignorable="x14ac x16r2 xr"> …

x14ac などの宣言は消え、Ignorable の値だけが残りました。register_namespace で x14ac を登録しても、パートの中で使っていなければ宣言は出力されませんでした。

弊社の​実測: 宣言を​補うと、​修復が​出なくなった

弊社は、お客様の既存の Excel の様式に値を書き込み、帳票として出す仕組みを作っています。その出力を開くと、毎回修復を求められる事象を切り分けました。

書き出しは2つの方式で、どちらも ElementTree で XML を書き直す工程を持っていました。

  • ひな形から別のブックを作る方式: ひな形を作るときに、シートの XML を ElementTree で書き直していた。
  • 受け取ったブックにシートを1枚足す方式: 受け取ったブックの styles.xml に書式を足し、ElementTree で書き直していた。
項目 内容
実測の日 2026年9月
Excel Mac 版の Microsoft Excel(AppleScript で開閉を自動化。版の番号は記録していない)
書き出し Python 3.14 の xml.etree.ElementTree
検証の道具 Open XML SDK 3.5.1(.NET)

結果は次のとおりです。お客様の様式の原本は、同じ Excel で修復を求められずに開きました。原因は様式ではなく、書き出しの側にありました。

ファイル 修復
お客様の様式の原本(対照) 出ない
別のブックを作る方式の出力 出る(シート3枚を置き換え・calcChain.xml の記録を削除)
同・Ignorable の宣言だけ補った版 出る(シート1枚だけ置き換え)
同・Requires の宣言も補い、calcChain.xml を外した版 出ない
シートを足す方式の出力 出る(styles.xml を削除)
同・styles.xml の宣言だけ補った版 出ない

Ignorable の宣言だけを補った版で残った1枚は、Requires="x14" を持つシートでした。x14 の宣言も落ちていたためです。

シートを足す方式で欠けていたのは、styles.xml の mc:Ignorable が挙げる x14ac と x16r2 の宣言でした。足したシート自体は、mc の属性と要素を落としてから書き出していたので、無傷でした。

修復のあと、Excel は修復の記録(ログ)を XML で残します。シートを足す方式の出力では、ログに次の行がありました。

削除されたパーツ: /xl/styles.xml パーツに XML エラーがありました。  (スタイル) HRESULT 0x808c0002
修復されたレコード: /xl/worksheets/sheet1.xml パーツ内のセル情報

openpyxl で​読めても、​Excel は​修復を​求める

この壊れ方は、弊社が出す前に回していた検査を、全部すり抜けました。実際の Excel と Open XML SDK だけが見つけました(SDK は後から確かめました)。

検査 この壊れ方を見つけたか
パートの差分・値の読み戻し 見つけない
openpyxl での読み直し 見つけない
LibreOffice での PDF 化 見つけない
Open XML SDK の検証 見つけた(互換性の誤り)
実際の Excel で開く 見つけた(修復を求めた)

Open XML SDK の OpenXmlValidator は、誤りの種類を MarkupCompatibility として返しました。

openpyxl の文書は、openpyxl が Excel のファイルのすべての項目を読むわけではない、と書いています。openpyxl で読み直せることは、Excel で修復が出ないことの証拠になりません。

修復を求められたら、まずログを読み、どのパートが捨てられたかで分けます。

見え方 疑う所
置き換えられた・削除されたパーツに「XML エラー」「0x808c0002」 まず、そのパートの名前空間の宣言の欠け(弊社のログ3本は、どれもこれだった)
calcChain.xml の数式の記録が削除された 上の巻き添えのことがある。宣言を直してから見直す
宣言の欠けが0なのに、修復を求められる 別の層の誤り(落とし穴の節のパート名など)。Open XML SDK で開けるかを見る

Mac 版の Excel では、ログは次の場所に「結果の修復先」で始まる名前の XML で書かれました。

~/Library/Containers/com.microsoft.Excel/Data/tmp/

直し方​: ​書き直した​ XML に、​落ちた​宣言を​補う

弊社が実際に通した手順は次のとおりです。

  1. XML を ElementTree で書き直している所を、全部洗い出す(弊社では、ひな形の作成・シートの書き出し・styles.xml の書き直しなど)
  2. 書き直した直後に、互換性の属性が挙げる接頭辞のうち、宣言の無いものを先頭の要素に宣言し直す関数を通す。名前空間の URI が分からない接頭辞が出たら、補わずに止める
  3. ひな形にも同じ変換を当て、宣言を補う(弊社は同時に calcChain.xml も外した)
  4. 宣言の欠けを数える検査を、書き出しの自己検証の合格の条件に入れる
  5. 実際の Excel で出力を開き、修復を求められないことを確かめる

弊社の是正の後に作った出力4本(方式の違うものを含む)を同じ Excel で開き、4本とも修復を求められませんでした。

もう1つの直し方は、書き出すパートから mc の属性と要素を落とすことです。弊社が足したシートは、この形で無傷でした。

XML を文字列のまま書き換える方式なら、宣言は元のまま残ります。既存の様式に、パートを文字列で差し替えて書き込む方式は、Excel帳票への自動書き込みでファイルが壊れる理由にまとめています。

その記事の5つの検査は、部品が黙って消えていないかを見るものです。開くと修復を求められるかは、この記事の確かめ方の節の検査で見ます。

次のコードは、弊社が単離の実験で使った変換を縮め、欠けを数える check を足したものです。check は宣言の欠けを数え、fix は宣言を補い、ほかのパートは元のバイトのまま詰め直します。

import re
import sys
import zipfile

MC = "http://schemas.openxmlformats.org/markup-compatibility/2006"
KNOWN = {
    "mc": MC,
    "x14": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
    "x14ac": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac",
    "x15": "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main",
    "x15ac": "http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac",
    "x16": "http://schemas.microsoft.com/office/spreadsheetml/2014/main",
    "x16r2": "http://schemas.microsoft.com/office/spreadsheetml/2015/02/main",
    "xr": "http://schemas.microsoft.com/office/spreadsheetml/2014/revision",
    "xr2": "http://schemas.microsoft.com/office/spreadsheetml/2015/revision2",
    "xr3": "http://schemas.microsoft.com/office/spreadsheetml/2016/revision3",
    "xr6": "http://schemas.microsoft.com/office/spreadsheetml/2016/revision6",
    "xr10": "http://schemas.microsoft.com/office/spreadsheetml/2016/revision10",
}
ROOTS = "styleSheet|worksheet|workbook|sst|calcChain|comments|table|xdr:wsDr"
ROOT_RE = re.compile(rf"<({ROOTS})\b[^>]*>")


def missing_prefixes(xml):
    m = ROOT_RE.search(xml)
    if not m:
        return None, []
    tag = m.group(0)
    # ElementTree は mc の接頭辞を ns1 などに付け替えることがある
    mcp = re.findall(r'xmlns:([A-Za-z0-9]+)="' + re.escape(MC) + '"', xml)
    listed = []
    for p in mcp or ["mc"]:
        mm = re.search(rf'{p}:Ignorable="([^"]*)"', tag)
        if mm:
            listed += mm.group(1).split()
        for mm in re.finditer(rf'<{p}:Choice\b[^>]*Requires="([^"]*)"', xml):
            listed += mm.group(1).split()
    declared = set(re.findall(r"xmlns:([A-Za-z0-9]+)=", xml))
    return m, [p for p in dict.fromkeys(listed) if p not in declared]


def fix_part(xml):
    m, miss = missing_prefixes(xml)
    if not miss:
        return xml, []
    unknown = [p for p in miss if p not in KNOWN]
    if unknown:
        raise SystemExit(f"URI が分からない接頭辞: {unknown}")
    add = "".join(f' xmlns:{p}="{KNOWN[p]}"' for p in miss)
    tag = m.group(0)
    return xml[:m.start()] + tag[:-1] + add + ">" + xml[m.end():], miss


def main(mode, src, dst=None):
    zin = zipfile.ZipFile(src)
    rep, found = {}, []
    for n in zin.namelist():
        if not n.endswith(".xml"):
            continue
        try:
            x = zin.read(n).decode("utf-8")
        except UnicodeDecodeError:
            continue
        if mode == "check":
            miss = missing_prefixes(x)[1]
        else:
            x2, miss = fix_part(x)
            if miss:
                rep[n] = x2.encode("utf-8")
        if miss:
            found.append((n, miss))
    print(src, "宣言の無い接頭辞:", found or "なし")
    if mode == "check":
        return 1 if found else 0
    with zipfile.ZipFile(dst, "w", zipfile.ZIP_DEFLATED) as zout:
        for item in zin.infolist():
            data = rep.get(item.filename) or zin.read(item.filename)  # 直したパート以外は元のバイト
            zi = zipfile.ZipInfo(item.filename, date_time=item.date_time)
            zi.compress_type = zipfile.ZIP_DEFLATED
            zi.external_attr = item.external_attr
            zout.writestr(zi, data)
    return 0


if __name__ == "__main__":
    sys.exit(main(*sys.argv[1:]))

使い方は python mc_decl.py check 出力.xlsx(欠けがあれば終了コード1)と、python mc_decl.py fix 入力.xlsx 直した.xlsx です。

弊社は、宣言を欠かせた合成のファイルで、check が欠けを見つけ、fix の後に0になることを確かめました。

このコードは、先頭の要素を決まった8種の名前(styleSheet・worksheet など)で探します。

挙げていない種類のパートは、検査の外になります。ElementTree で既定の名前空間を登録せずに書き出すと、先頭が ns0:styleSheet になります。

その形では、このコードは欠けを見つけません(弊社の合成のファイルで確かめました)。書き出す前に、既定の名前空間を register_namespace("", …) で登録しておきます。

落とし穴: 実際に​踏んだ​もの

  • calcChain.xml が原因に見えた最初のログには、calcChain.xml の数式の記録の削除が出ていました。宣言を補った版ではこの記録が消え、原因ではありませんでした。
  • Ignorable だけ直しても、修復は残ったシートの中の mc:Choice Requires="x14" の宣言も落ちていました。先頭の要素の属性だけでなく、パートの中の Requires も見ます。
  • 修復は「害が無い」とは限らないログには、シートのパートを置き換えた版と、書式の定義のパート(styles.xml)を削除した版がありました。捨てられたパートによっては、回復した後の見た目が元と同じとは限りません。
  • 宣言の検査が通っても、別の層で修復を求められた2026年9月、別の帳票でシートを1枚足すとき、パート名に日本語を使いました。宣言の検査は通り、弊社が実際の Excel で開くと修復を求められました(版の番号は記録していません)。

最後の件では、Open XML SDK はファイルを開く段階で止まり、次の文を出しました。

Part URI is not valid per rules defined in the Open Packaging Conventions specification

ECMA-376 の Part 2(2021年の第5版)は、ZIP の中の名前を ASCII だけにし、ASCII でない文字はパーセントの形に変えると定めています(7.3.3・7.3.4 節)。

ASCII でないパート名への対応は、推奨にとどめ、実装に求めていません(6.2.2.2 節)。

弊社のファイルでは、生の日本語が、ZIP の中の名前・[Content_Types].xml・関係の定義(.rels)の3か所に入っていました。

パート名を sheet4.xml のような ASCII の名前にし、docProps/app.xml のシートの数と名前を実体に合わせて直しました。

確かめ方​: 出す前に​3つの​検査を​通す

弊社は、この件の後、新しい形の xlsx を出す前に次の3つを通す形にしました。1つ目と2つ目は機械で回し、3つ目は Excel で1本開きます。

  1. 宣言の欠けの検査上のコードの check のように、互換性の属性が挙げる接頭辞が全部宣言されているかを数え、0を合格にする
  2. Open XML SDK の検証OpenXmlValidator で検証し、MarkupCompatibility の誤りと、開けない(パッケージの誤り)が無いかを見る
  3. 実際の ExcelExcel で1本開き、修復を求められないことを見る

1つ目の検査を作ったら、正しいファイルで止まらない(誤検出が無い)ことも確かめます。弊社が実際に使っている検査(上のコードとは別に作ったもの)は、お客様の原本の約50本で誤検出が0でした。

2つ目は、弊社では次の形で流しています(.NET と Open XML SDK 3.5.1。要点だけに縮めたもの)。

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;

foreach (var path in args)
{
    try
    {
        using var doc = SpreadsheetDocument.Open(path, false);
        var validator = new OpenXmlValidator(FileFormatVersions.Office2016);
        foreach (var e in validator.Validate(doc))
            Console.WriteLine($"{e.ErrorType} | {e.Part?.Uri} | {e.Description}");
    }
    catch (Exception ex)
    {
        Console.WriteLine("OPEN FAILED: " + ex.Message);
    }
}

SDK の誤りの種類には、Schema・Semantic・Package・MarkupCompatibility の4つがあります(Microsoft の ValidationErrorType の文書)。

弊社は SDK の結果を Excel の判定の代わりにはせず、最後は Excel で開いて確かめます。

3つ目は、弊社の調べでは AppleScript で Excel を開閉し、修復の画面の有無とログを自動で読みました。手で1本開いて見るだけでも、この記事の壊れ方は見つかります。

自力で​どこまで​やれるか

書き出しのコードを自社で持っていて、XML を書き直す所が少なく、出す前に Excel で開く工程を足せるなら、自力で足ります。直しは、書き直した直後に宣言を補う関数を通すことです。

自力の壁は次の3つです。

  • XML を書き直す所が、ひな形の作成・書き出し・書式の追加などに散っていて、全部を洗い出す必要がある
  • 修復のログから、どのパートがなぜ捨てられたかを読み、宣言の欠けか別の層の誤りかを分ける必要がある
  • 自作の検査・SDK・実際の Excel の3つを、出す前の工程として毎回回す仕組みが要る

外注する​場合の​判断基準

外注の分かれ目は、帳票を出すたびに、Excel で修復が出ないことを確かめる工程を、自社で持ち続けられるかです。外注するなら、見積もりを比べる前に次の3点を確かめてください。

  • 受け入れの検査に、実際の Excel で開く確かめが入っているか
  • openpyxl での読み直しや値の照合だけで「壊れていない」としていないか
  • 確かめを通らない出力を、出さずに止める作りになっているか

ゴムマリでは、既存の Excel の様式へ書き出す業務を含め、1つの業務を回す AI エージェントを御社の業務に合わせて作る仕事を、AIエージェント導入として承ります。決めた確かめを通らない出力は、出さずに止める作りにします。

お渡しするのは、その業務の AI エージェント、判断の基準を書いた文書、使い方の手順です。料金は1つの業務ごとに初期50万円から、月額5万円から、初期構築は4週間からです。

月額には、出す前の確かめを保ち、足していくことを含みます。進め方は相談からご連絡ください。

次の​一歩

修復を求められる帳票を1本選び、ZIP として開いて、styles.xml とシートの XML の先頭を見てください。mc:Ignorable に並ぶ接頭辞のうち、xmlns: の宣言が無いものがあれば、この記事の原因です。

宣言を補った版を Excel で開き、修復が出なくなるかを確かめます。出なくなったら、書き出しのコードの、XML を書き直している所を全部洗い出します。

帳票を自動で作るときに、数字が正しいことを仕組みで確かめる方法は、既存Excel様式を自動生成するときの品質保証にまとめています。

関連記事: Excel帳票への自動書き込みでファイルが壊れる理由/既存Excel様式を自動生成するときの品質保証/Python で値を書いた Excel の計算結果が古いままの理由

この記事を書いた人

代表 村山悠太のポートレート

村山 悠太(ゴムマリ代表)

ワークスアプリケーションズで大手企業向けERPの営業と導入を担当し、外資系SaaS企業と国内大手放送局で販路と新規事業の立ち上げ、AI学習用データを扱うAIスタートアップ2社でマーケティングと営業を担った。2024年10月から生成AIの実装に入り、いまは大手企業の現場で、AIエージェントを要件定義から運用まで手がけている。

代表の経歴を見る

FAQ

よく​ある​質問

openpyxl で開いて保存しただけでも、修復を求められますか?

弊社が切り分けたのは、XML を ElementTree で読み書きした場合です。openpyxl の保存で修復が出るかは確かめていません。openpyxl の文書は、すべての項目を読むわけではないので、開いて同じ名前で保存すると図形が失われる、と警告しています。

「はい」で回復して開けば、そのまま使えますか?

捨てられたパートによります。弊社の修復のログには、シートのパートを置き換えた版と、書式の定義のパート(styles.xml)を削除した版がありました。回復した後の中身が元と同じとは限らないので、回復に頼らず、修復が出ないファイルを出してください。

修復のログに calcChain.xml が出ています。calcChain.xml を消せば直りますか?

弊社の実測では、calcChain.xml は原因ではなかったとみています。`Ignorable` の宣言だけを補った版でも、calcChain.xml を残したまま、その削除の記録が消えました。シートのパートが置き換えられた巻き添えで、計算の記録が削除されていたとみています。

Windows の Excel でも同じように出ますか?

弊社の実測は Mac 版の Microsoft Excel だけで、Windows 版では確かめていません。宣言の無い接頭辞を互換性の属性に挙げることは、ECMA-376 の仕様で非適合です。どの版で開くかによらず、出す前に宣言の欠けを検査で0にしておきます。

自作の検査が全部通っていても、修復を求められることはありますか?

あります。弊社では、パートの差分・値の読み戻し・openpyxl での読み直し・LibreOffice での PDF 化がすべて通ったファイルで、Excel が修復を求めました。検査は、見ている層の壊れ方しか見つけません。出す前に Excel で1本開いて確かめます。

Related

関連

ご相談は​こちらから

相談は無料です。

相談する