PowerCMS X ブログ
2022-12-15
ウェブサイトのリニューアルなどの工数の多くを占めるデータ移行。PowerCMS XではWebスクレイピングによるデータ移行をサポートしており、大量のコンテンツを管理画面操作で簡単に移行できます。ただし、移行したHTMLはリニューアル後のコーディングルールに沿っていないことが前提であり、また、ウェブアクセシビリティ対応などが要件として入っている場合、単に移行して終わり、とはいきません。
PowerCMS X ver.3.08で追加された「AxeRunner」は機械的に検証可能な部分について、CMSから出力されたすべてのページのアクセシビリティチェックを定期的に行うことができます。また、The Nu Html Checker等 を使って、HTMLの文法違反などについては機械的に検証しておくと良いでしょう。
開発のきっかけになった案件ではvNu アイコン別ウィンドウで開きますでコマンドラインからNu Html Checkerを使い1時間に2回エラーを TSVに書き出すようにして進めました
ある案件の際に問題となったのが、大量のHTMLの文法違反です。単純な間違いももちろんあるのですが、移行元のサイトに古いHTMLが残っている場合には、最新のHTMLでは廃止された要素やタグ属性が使われていて、これが大量にエラーを吐きます。アクセシビリティ上の問題の有無以前に、妥当なHTMLではない、という時点で大量のエラーが出るため、その対応に追われてしまうことになり、本来修正すべき点への対応に時間を割けないという本末転倒の状態になります。また、廃止された要素や属性をブラウザがサポートしているうちは良いですが、サポートされなくなることでコンテンツの意味合いが異なってしまう懸念があります。
#!/bin/bash
url=https://www.example.jp
doc_root=/var/www/html
num_path_tsv=$HOME/var/num-path.tsv # 案件固有の管理番号と URL のパスの対応を定義した TSV ファイル
output_tsv=$doc_root/vnu-results.tsv
cd /tmp &&
wget --quiet --timestamping https://github.com/validator/validator/releases/download/latest/vnu.linux.zip{,.sha1} &&
echo "$(cat vnu.linux.zip.sha1) vnu.linux.zip" | sha1sum --check --quiet - &&
tempdir=$(mktemp -d) &&
tempfile=$(mktemp --tmpdir=$tempdir) &&
cd $tempdir &&
unzip -q /tmp/vnu.linux.zip &&
ionice -c3 vnu-runtime-image/bin/vnu --skip-non-html --errors-only --stdout $doc_root |
perl -E'my%u;while(<>){if(m,^"file:'$doc_root'([^"]+)":(.+),){$a=$u{$1}||[];push(@$a,$2);$u{$1}=$a}}say"#\tURL\tHTML error";for$k(sort keys%u){($n=`grep $k '\'$num_path_tsv\''`||"")=~s/\t.*//s;@a=@{$u{$k}};$v=shift@a;say"$n\t'$url'$k\t$v";say"\t\t$_"for@a}' > $tempfile &&
chown apache: $tempfile && # 任意
mv $tempfile $output_tsv &&
rm -rf $tempdir
※ y君が設定してくれました。
加えてAxeRunnereプラグインで「axe-core」による自動検証を1日1回実行するように設定しました
HTML Tidy アイコン別ウィンドウで開きますはPHPのバインディングがあり、PowerCMS Xのプラグインとして、静的ファイル出力時のフィルタとして組み込んでみました(データそのものは変えずに静的HTML出力時に変換する)。こうすることで、DBなどを誤って書き換えてしまい、元に戻せなくなることを避けることができます。不足している閉じタグを補完してくれたり、一定の効果があることがわかりましたが、cleanを指定して実行すると、必要なdiv、spanタグが消えてしまうケースなどの副作用もありました。また、廃止されたタグ属性を単純に削除してしまうと、ページの表示が元のサイトで意図していたものと異なってしまうことがあります。これを防ぐために、見栄えを指定するようなタグやタグ属性は単純に削除するのではなく、CSSに置き換えて、見た目に関してできるだけ元のページで意図したものを再現しつつ、修復を図る必要がありました。
そこで、HTML Tidyによる最低限の修復に加え、独自の処理を実装したものが、PowerCMS X ver.3.09で追加になった「HTMLTidy」プラグインです(最終的には HTML Tidyを用いた修正よりも独自のDom操作によるクリーンアップ処理の方が多くなったため、PHP拡張がインストールされていない環境でも利用できるようにしました)。何を実行するかについては、主に環境変数で指定します。環境変数ごとに、どのような修復を行うかについてご紹介します。※ 以下に、このプラグインを作るきっかけとなった案件でよく見られたものや、実装の意図などを追記しています。
開発のきっかけとなった大型の案件では、1万件を超える文法エラーの90%近くを修復できました。
HTML5で追加されたタグを認識させます。初期値は trueです。
HTMLTidyによるマークアップの修復を行います。空の要素などは削除されます。初期値は falseです。
修正後の HTMLを再度 DomDocumentで loadHTMLし、saveHTMLします。初期値は falseです。
trueを指定すると再構築時に文書全体に対して処理を行います。初期値は falseです。
廃止された要素を CSSに置き換えを行う時、インライン CSSではなく classを付与して HTMLの head内に styleタグを追加します。初期値は falseです。
※ リニューアル後の新しいデザインより「弱く」適用するという狙いから、このように指定できるようにしました。また、同じ指定がある時、インラインで指定せず、纏めることができます。
<td class="class1 class2" cellpadding="2" align="right" bgcolor="black">
指定なしだと、以下のようになります。
<td class="class1 class2" style="text-align:right;padding:2px;background-color:black">
指定ありだと、以下のようにハッシュで生成された値のclassを追加して、head内にCSSを追加します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<style>.tidy-o44zxA{text-align:right;padding:2px;background-color:black}</style>
...
<td class="class1 class2 tidy-o44zxA">
※ 以下の例では、tidy_css_to_head 指定のある変換例で紹介します。
tidy_css_to_head指定のある時、要素に追加する class名のプレフィックスです。初期値は「tidy」です。
テーブル(table, tr, th, td)のクリーンナップを行います。廃止された属性を CSSに変換します('width', 'height', 'align', 'valign', 'cellpadding', 'nowrap', 'bgcolor')。また、tdタグに scope属性があったら削除します。初期値は trueです。
table要素の border属性を削除します。初期値は trueです。
指定した値にマッチする class名が付与されている table要素に role="presentation"を追加します。初期値の指定はありません。
※ レイアウト目的であろうテーブルが存在し、table class="layout" のような指定が見られたので、role="presentation"を追加するような設定を設けました。
imgタグのクリーンナップを行います。廃止された属性を CSSに変換します('vspace', 'hspace', 'border')。不正な width, height を削除します(空文字・数字を含まないなど)。alt属性のない img要素に alt="" を追加します。初期値は trueです。
img要素が aタグの中にある時、aタグの要素内容のテキストと画像の alt属性値が重複している時、alt属性値を空にします。「2」を指定すると、aタグの要素内容のテキストと画像の alt属性値が同一の時のみ、属性値を空にします。tidy_clean_imageが有効な時のみ作用します。初期値は「0」です。
<a href="/">ホーム <img src="/imgs/icon_home.png" alt="ホーム"></a>
を以下のように修正します。
<a href="/">ホーム <img src="/imgs/icon_home.png" alt=""></a>
2を指定したときは、上記のケース(一致)は修正しますが、下記のケース(部分一致)は修正しません。
<a href="/">ホームへ <img src="/imgs/icon_home.png" alt="ホーム"></a>
※ 自分的には、これが結構お気に入りです。
img要素に指定できない属性を削除します。初期値は「longdesc,name」です。longdescについては alt属性値にマージされます。
ブロック要素の align属性を CSSの text-alignに置換します。対象は('p', 'div', 'dd', 'li')要素で、初期値は trueです。 trueの代わりに要素名の配列を指定することもできます。
br要素に指定された clear属性を CSSに変換します。初期値は trueです。
URLに指定できない文字列を置き換えます。初期値は(' ' => '', ' ' => '%20')です。
a要素の name属性を id属性に置き換えます。初期値は falseです。
font要素を span要素に置き換えて color, size, face属性値を CSSに変換します。初期値は trueです。
<font size="7" color="red" face="MS Pゴシック">変換のサンプル</font>
上記のHTMLを以下のように変換します。
<style>.tidy-KsjFHw{font-size:xxx-large;color:red;font-family:"MS Pゴシック"}</style>
...
<span class="tidy-KsjFHw">変換のサンプル</span>
size属性値とCSSは以下のルールで置き換えます。
1 → x-small
2 → small
4 → large
5 → x-large
6 → xx-large
7 → xxx-large
+1,+2は120%×数字、-はその逆
ちなみに以下で取り上げるbig要素は「larger」となります。
設定で指定した廃止された要素を置き換え可能な要素に置き換えます。属性値はそのまま引き継がれます。初期値は{"acronym":"abbr","s":"del","strike":"del","dir":"ul","big":"span","tt":"span","u":"span","center":"div"}です。
<acronym class="class1" title="North Atlantic Treaty Organisation">NATO</acronym>
以下のように変換します。
<abbr class="class1" title="North Atlantic Treaty Organisation">NATO</abbr>
center, big, tt, u要素にはスタイルを付与します。
<center>
<big>文字拡大</big>
<tt>等幅テキスト</tt>
<u>アンダーライン</u>
</center>
以下のように変換します。
<style>.tidy-eUSLNg{font-size:larger}.tidy-1XKNSg{font-family:monospace}.tidy-LzbG6g{text-decoration:underline}.tidy--IcXnw{text-align:center}</style>
...
<div class="tidy--IcXnw">
<span class="tidy-eUSLNg">文字拡大</span>
<span class="tidy-1XKNSg">等幅テキスト</span>
<span class="tidy-LzbG6g">アンダーライン</span>
</div>
applet要素を object要素に置き換えます。初期値は trueです。
dl要素に必要な子要素がない時、必要な要素を補完します。dt要素もdd要素も存在しない場合、p要素に置き換えるか、内容がなければ要素自体を削除します。また、置くことのできない要素が直接置かれている時に、直近の dt、dd要素にマージします。初期値は trueです。
ul、ol要素に必要な子要素(li要素)がない時、必要な要素を補完します。また、置くことのできない要素が直接置かれている時に、直近の li要素にマージします。初期値は trueです。
area要素の nohref属性(廃止)を削除し、coords内のスペースを削除します。初期値は trueです。
iframe要素の frameborder属性(非推奨)を削除します。初期値は trueです。
lang属性の誤りを修正します。初期値は指定なしです。単に trueを指定した場合 jp を ja に置き換えます。他のパターンをハッシュで指定することもできます。初期値は「{"jp":"ja"}」です。
※ 他にも、様々なものが存在しました。{"jp":"ja","eん":"en","e":false,"po":"pt","eb":"en","vn":"vi","tu":"tr","cn":"zh","sp":"es"} (falseを指定したものは属性自体を削除します)
カンマ区切りで指定した属性の属性値が空文字であるものを削除します。初期値はありません。
href属性を含み、name属性のない a要素の要素内容が空(または空文字のみ)の時、a要素を削除します。初期値は falseです。
コメントノードを削除します。初期値は trueです。
'table', 'ul', 'ol', 'dl'要素内に直接置かれた全角スペースを半角スペースに置き換えます。初期値は trueです。
※ 結構ありました。
「“」を「“」に、「”」を「”」に、「—」を「—」置き換えます。初期値は falseです。
文字コードが UTF8のみである時に指定します。初期値は trueです。
不正なコードポイントを UTF8文字に置き換えます。初期値は falseです。
整形後の HTMLを折り返す文字数を指定します。初期値は「0」です。
PHPの「tidy_parse_string」に渡す第2引数のハッシュを指定します。初期値の指定はありません。オプションについての説明は » http://api.html-tidy.org/#quick-reference を参照ください。
その他の設定はプラグイン設定で指定します。適用する範囲を絞り込んだりすることで、意図しない変換を防ぐことができます。
ページ全体に適用せずに、テンプレートの特定部分だけに処理を限定できます。
PowerCMS Xを利用したウェブアクセシビリティが要件に指定されているウェブサイトのリニューアルでは、リニューアル後のテンプレートを整備した後に、以下のような手順でデータ移行を行います。