仕事柄、マイクロソフトのExcelからは逃げられません。もう呪いですよここまで来ると。
サーバーに置かれた誰が作ったかも判らないエクセルファイルを使っていろいろデータのやりとりを日々行っているわけですが、いろんな部署から不特定多数のアクセスがあると、知らない間にいろいろと汚染されていることがあります。
例えばスタイル。恐ろしい数のスタイルがいつの間にか設定されており、ファイルサイズが膨れ上がったり、旧ファイル形式では書式の破壊を引き起こしたり。
これはマイクロソフトの公式でも「スタイル削除のVBA」を公開するほどの公認不具合ですが、どういうわけかこれでは消せない、手動で削除しても消せない完全なるゴミスタイルがあったりして気分が悪いです。
ゴミスタイルの名前に特定地域の地名が入ってたりすることから該当支店がなにかやらかしてるんだと思うんですが、イタチごっこになっていて手がつけられません。タチの悪いことに、これらのゴミスタイルはセルのコピーやシートのコピーを機会に別ファイルに乗り移ったりします。
そしてもう一つ、外部参照の残骸です。
どうしても消えない、どこに設定されているか判らないリンクが悩みの種でした。
Google先生などで訊いてみても、出てくるのは「リンクの編集で参照元を変更する」とか「名前に設定されている場合は名前の管理から消す」とか「条件付き書式に設定されている場合は〜」「オブジェクトに設定されている場合は~」とか。
全部確認しました、シートのどこにも、オブジェクトのどこにも、名前にも条件付き書式にも該当のリンクは見つかりません。リンクの解除も受け付けない、これは一体どうすればいいのか。
意外なところに手段が転がっていました。
実はExcelのファイル形式、.xlsxや.xlsmはzipファイルなんですって。へー。
ものは試しに拡張子をzipに変えてみると……おお、確かに内部データが見えます。
「xl」フォルダの中身を見ていくと、さらにいくつかのデータとフォルダが。その中に「externalLinks」というフォルダを開くと、「externalLink1.xml」のファイルと「_rels」というフォルダが。そのフォルダの中には「externalLink1.xml.rels」というファイルが。
ファイルを開いてみると……消せなかったゴミリンクが記載されているではありませんか。
これらのファイルを削除すると、なぜかexternalLinksのフォルダ自体が消えました。拡張子を元に戻し、ファイルを開くと、参照できない値が云々と言われてファイルの修復が始まりました。修復が終わると……リンク消えてますね。
もう一つ、スタイルの件。xlフォルダの配下に「styles.xml」というファイルがありました。 zipファイルの中身を直接編集はできないので、一旦デスクトップ等に「styles.xml」をコピー。これをテキストエディタで開きます。
「styles.xml」の中身はたった2行のテキスト……しかし、ファイルサイズは10MB超えてたりしますから、どれだけ見づらいか。テキストエディタで右端で折り返す、等の措置を執らないととてもじゃないが見られたものではありません。
「<csllStyles count="(数字)">」から始まって「</cellStyles>」で終わるタグ? の中に「<cellStyle name=」で始まる無数のスタイルがあります。その中には消せなかったスタイルが記載されています。
これを削除……ただし、全て削除してしまうとファイル内の書式が破壊されてしまう事象を確認したので、どれか最低一つは残す必要があるようです。
xfId="0"の"標準"だけ残して消してしまいます。
ファイルをzipに戻して拡張子を元に戻してファイルを開くと、今まで消せなかったゴミスタイルが消えていました。
このファイルを上書き保存して、再度zip化してstyles.xmlを確認すると、先ほどのcountは3に修正され、デフォルトだけに戻るようです。この際、cellStyle name以外のゴミも自動で取り除かれるようです。上書き保存して一連の作業は完了、ということですね。
方法としてはものすごい邪道だと思うんですが、もし同様の悩みを抱えている方がいたら「自己責任において」試してみてはいかがでしょうか。下手すりゃファイルが壊れる方法なので、当然バックアップを取ってから。
追記:
外に引っ張り出してきたstyle.xmlから余分なスタイルを削除するコードです。
ダイアログからstyle.xmlを選択すればOK……ただし、「標準」のスタイルが残っていないと書き込みを行いません(スタイル全削除になってファイルが壊れるからです)。
しつこいようですが、バックアップは確実に取ってから実行してください。
Sub style_xml編集()
Dim fName As String
Dim i As Long
Dim Buf As String
Dim Style
Dim Tmp
Dim e As Boolean
fName = Application.GetOpenFilename("スタイル,*.xml")
If fName = "False" Then End
With CreateObject("ADODB.Stream")
.Charset = "UTF-8"
.Open
.LoadFromFile fName
Buf = .readtext
.Close
End With
Style = Split(Buf, vbCrLf)
Tmp = Split(Style(1), ">")
Style(1) = ""
For i = 0 To UBound(Tmp) - 1
If Left(Tmp(i), 16) = "<cellStyle name=" Then
If InStr(Tmp(i), "<cellStyle name=""標準"" xfId=""0""") > 0 Then
Style(1) = Style(1) & Tmp(i) & ">"
e = True
End If
Else
Style(1) = Style(1) & Tmp(i) & ">"
End If
Next i
If e = False Then
MsgBox "標準 xfId=""0""のスタイルが見つかりませんでした。処理を中止します"
End
End If
With CreateObject("ADODB.Stream")
.Charset = "UTF-8"
.Open
.writetext Style(0), 1
.writetext Style(1), 0
.savetofile fName, 2
.Close
End With
End Sub
追記:
スタイルを自動で消せる部分は消してしまいましょう、ということで、私が使っているスタイル削除です。
消せないスタイルがあった場合は警告を出しますので、その場合は上記のstyle_xml編集を使用して消すようにしています。
あと、無駄に処理時間を出すようにしています。通常用途では必要無いはずです。
……スタイル削除をサボってると、こんだけ時間を無駄にしますよ、ということを職場に知らしめるためです。スタイル数5万を超えるようなファイルがゴロゴロしていましたので。
Sub スタイル削除()
Application.ScreenUpdating = False
Dim fName As String
Dim bName As String
Dim a As Long
Dim c As Long
Dim z As Long
Dim s As Object
Dim w As Worksheet
Dim sTime As Date
Dim eTime As Date
z = Cells(Rows.count, 1).End(xlUp).Row + 1
If z < 5 Then z = 5
fName = Application.GetOpenFilename("スタイル削除,*.xls*")
If fName = "False" Then End
Workbooks.Open (fName), ReadOnly:=True
sTime = Now
bName = ActiveWorkbook.Name
bName = Left(bName, InStr(bName, ".xls") - 1) & "after" & Mid(bName, InStr(bName, ".xls"))
For Each w In Worksheets
If w.ProtectContents = True Then w.Unprotect
Next
On Error Resume Next
For Each s In ActiveWorkbook.Styles
If Not s.BuiltIn Then
s.Delete
c = c + 1
End If
If Err.Number = 1004 Then
a = a + 1
Err.Number = 0
End If
Next
ActiveWorkbook.Close SaveChanges:=True, Filename:=ActiveWorkbook.Path & "\" & bName
Cells(z, 1).Value = fName
Cells(z, 2).Value = c
eTime = Now
Cells(z, 3).NumberFormatLocal = "h:mm:ss"
Cells(z, 3) = Format(eTime - sTime, "h:mm:ss")
If a > 0 Then
Cells(z, 1).Interior.ColorIndex = 6
MsgBox "消せなかったスタイルが存在します。style.xmlの直接修正が必要です", vbExclamation
End If
Application.ScreenUpdating = True
End Sub