Technically Impossible

Lets look at the weak link in your statement. Anything "Technically Impossible" basically means we haven't figured out how yet.

「早起き生活」のバックアップ・データをExcelへインポートする

f:id:espio999:20210328134533p:plain
2005年9月に開始した、起床時刻を記録するwebサービス「生活改善応援サイト 早起き生活」が3月末日で終了する。日々の記録を参照すると、一番古い記録は2005年11月30日のものだった。利用期間は15年4か月に及んだ、息の長い付き合いだった。
www.hayaoki-seikatsu.com

このサービスには起床時刻以外に”今日の気分(本文)”という、文書を記録する項目があり、日記やブログとしても活用できるものだった。起床時刻の記録だけでなく、そのときの出来事、気分、思索などの記録にも用いられていたことだろう。そのための配慮か、記録のバックアップを取得できる機能が提供されている。それが冒頭の画像だ。

バックアップは、1年分を単位としてXML形式のテキストとして取得できる。出力されたテキストをエディタなどにコピーして、任意のファイルへ保存することになる。
1年分ごとに複数のXMLファイルとして保存しておいても良いのだが、単一のExcelファイルに取り込み、1年分を1タブとして記録しておくのが、シンプルで良いと思う。

この投稿では、そのための手順、注意点とともに、バックアップ・データをより厳密に理解するために、そのスキーマ定義(XSD)を紹介する。

バックアップ・データ(XML文書)の構造

例えば、次のような記録があったとしよう。1日分の記録だが、二度寝を繰り返したのか、昼寝をしたのか起床時刻が3つ記録され、本文とともに、3つのコメントが含まれている。
バックアップ・データでは、該当箇所は次のように記録されることになる。
f:id:espio999:20210328134626p:plain


バックアップ・データ

</diaries>
~ 省略 ~
<diary>
	<date>2021/03/28</date>
	<risingtimes>
		<risingtime>10:42</risingtime>
		<risingtime>12:06</risingtime>
		<risingtime>17:30</risingtime>
	</risingtimes>
	<body>ここに本文があります。</body>
</diary>
</diaries>


ここから、バックアップ・データは次の構造であることが分かる。

diaries 1年分の日記
diary 1日分の日記
date 日付
risingtimes 1日の起床時刻
risingtime 個々の起床時刻
body 今日の気分(本文)

コメントがバックアップ・データに含まれていないのは、それがバックアップ対象外だからだ。

インポート前の注意点

出力したバックアップ・データをXMLファイルとして保存する。このファイルをExcelへインポートするのだが、その前に注意してほしいことがある。それは”今日の気分(本文)”のテキストだ。
バックアップ・データ内では、該当テキストの前後にbodyタグが付与されている。このテキスト中にエスケープの必要な文字が含まれていた場合、Excelでのインポートが不適切に実行されるか、エラーとして受付されない。
f:id:espio999:20210328141520p:plain

事前確認として、インポート前にブラウザで開いてみることをお勧めする。バックアップ・ファイルが正常であれば、次のように表示されるのだが、


正常な表示
f:id:espio999:20210328134740p:plain

問題があれば、次のようなメッセージが表示されるはずだ。


エラー表示
f:id:espio999:20210328134802p:plain

このような場合、”今日の気分(本文)”のテキストに問題となる文字が含まれており、それらを置換する必要がある。典型的なのは、次のような記号文字だ。これらを置換候補の様に置き換える。

記号文字 置換候補
& &amp;
< &lt;
> &gt;

その他の記号文字については「html 特殊文字」で検索するなどして調べてみて欲しい。
ja.wikipedia.org

Excelでのインポート

XMLファイルがブラウザで正常に表示されるならば、Excelにインポート可能だ。ファイル・メニューから次の機能を選択して、データをインポートする。

データ > その他のデータソース > XMLデータインポートから

f:id:espio999:20210328134937p:plain
データは次のように取り込まれる。前述の複数の起床時刻が複数行にわたって記録されており、”今日の気分(本文)”が各行にコピーされているのが分かる。これはXMLをインポートするに際する、Excelの仕様だ。


インポート結果
f:id:espio999:20210328140106p:plain

1年分のバックアップ・データを、1シートに割り当てる前提で、バックアップ・データごとに異常の作業を繰り返せばよい。

スキーマ定義、XSDファイル

f:id:espio999:20210328141619p:plain
Excelでのインポートでは、スキーマが自動生成された。もしスキーマを自分自身で定義する必要があるならば、バックアップ・データの構造を、もう少し追いかけてみる必要がある。

”バックアップ・データ(XML文書)の構造”で触れたとおり、バックアップ・データは1年分で1ファイルなので、diariesタグは、1ファイル中に1つだけ存在することになる。
そしてdiaries中に、毎日の記録として、1日、一つのdiaryタグが配置される。言うなればdiariesが日記帳、diaryが日記ということだ。

日記(diary)は、次の情報で構成される。

  • 日付
  • 起床時刻
  • 今日の気分(本文)

この中で、起床時刻以外の情報は、単一の日記中に一つだけ存在し、起床時刻だけが複数回、記録される可能性がある。

実際、起床時刻は"risingtime"タグとして記録されるのだが、複数の起床時刻が"risingtimes"という単一のタグでまとめられている。

ここまでの構造をスキーマとして定義するならば、XSDファイルは次のようになるだろう。


スキーマ定義

<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <xsd:element name="diaries" type="日記帳" />

  <xsd:complexType name="日記帳">
    <xsd:element name="diary" minOccurs="1" maxOccurs="unbounded" type="日記" />
  </xsd:complexType>

  <xsd:complexType name="日記">
    <xsd:sequence>
      <xsd:element name="date" type="xsd:date" />
      <xsd:element name="risingtimes" type="起床時刻" />
      <xsd:element name="body" type="xsd:string" />
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="起床時刻">
    <xsd:element name="risingtime" minOccurs="1" maxOccurs="unbounded" type="xsd:time" />
  </xsd:complexType>

</xsd:schema>


これをXSDファイルとして保存し、バックアップ・データのXMLファイル中のdiariesタグ中に、次のように指定すればよい。

diariesタグ

<diaries
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="diary.xsd">