PowerCMS X ブログ

2022-12-15

ウェブサイトリニューアル案件で移行後のHTMLを検査〜自動的に修正する

ウェブサイトリニューアル案件での古いHTMLへの対応問題

ウェブサイトのリニューアルなどの工数の多くを占めるデータ移行。PowerCMS XではWebスクレイピングによるデータ移行をサポートしており、大量のコンテンツを管理画面操作で簡単に移行できます。ただし、移行したHTMLはリニューアル後のコーディングルールに沿っていないことが前提であり、また、ウェブアクセシビリティ対応などが要件として入っている場合、単に移行して終わり、とはいきません。

PowerCMS X ver.3.08で追加された「AxeRunner」は機械的に検証可能な部分について、CMSから出力されたすべてのページのアクセシビリティチェックを定期的に行うことができます。また、The Nu Html Checker等 を使って、HTMLの文法違反などについては機械的に検証しておくと良いでしょう。

vnuでコマンドラインからNu Html Checkerを使うようにした

開発のきっかけになった案件ではvNu 別ウィンドウで開きますでコマンドラインからNu Html Checkerを使い1時間に2回エラーを TSVに書き出すようにして進めました

ある案件の際に問題となったのが、大量のHTMLの文法違反です。単純な間違いももちろんあるのですが、移行元のサイトに古いHTMLが残っている場合には、最新のHTMLでは廃止された要素やタグ属性が使われていて、これが大量にエラーを吐きます。アクセシビリティ上の問題の有無以前に、妥当なHTMLではない、という時点で大量のエラーが出るため、その対応に追われてしまうことになり、本来修正すべき点への対応に時間を割けないという本末転倒の状態になります。また、廃止された要素や属性をブラウザがサポートしているうちは良いですが、サポートされなくなることでコンテンツの意味合いが異なってしまう懸念があります。

  • まず、vNu のエラーのみを TSV ファイルにするシェルスクリプトをサーバーに設置して、1時間に2回、エラーのみをTSVファイルに出力するように設定、エラーがないかを確認しながら進めるようにしました(この段階では大量のエラーが存在しました)。
  • AxeRunnerで1日に1回、すべてのページの機械的なアクセシビリティチェックを実行するようにしました。
  • HTMLの修復に「HTML Tidy」が使えないか検討しました。

vNu で特定ディレクトリ配下の HTML ファイルのエラーを TSV ファイルにするシェルスクリプト

#!/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君が設定してくれました。

AxeRunnerプラグインによるレポート

加えてAxeRunnereプラグインで「axe-core」による自動検証を1日1回実行するように設定しました

HTML Tidyのプラグイン化

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%近くを修復できました。

tidy_html5

HTML5で追加されたタグを認識させます。初期値は trueです。

tidy_cleanup

HTMLTidyによるマークアップの修復を行います。空の要素などは削除されます。初期値は falseです。

tidy_re_save_html

修正後の HTMLを再度 DomDocumentで loadHTMLし、saveHTMLします。初期値は falseです。

tidy_outputfilter

trueを指定すると再構築時に文書全体に対して処理を行います。初期値は falseです。

tidy_css_to_head

廃止された要素を 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_class_prefix

tidy_css_to_head指定のある時、要素に追加する class名のプレフィックスです。初期値は「tidy」です。

tidy_clean_table

テーブル(table, tr, th, td)のクリーンナップを行います。廃止された属性を CSSに変換します('width', 'height', 'align', 'valign', 'cellpadding', 'nowrap', 'bgcolor')。また、tdタグに scope属性があったら削除します。初期値は trueです。

tidy_clean_table_border, tidy_clean_table_zero_border

table要素の border属性を削除します。初期値は trueです。

tidy_table_presentation_class

指定した値にマッチする class名が付与されている table要素に role="presentation"を追加します。初期値の指定はありません。

※ レイアウト目的であろうテーブルが存在し、table class="layout" のような指定が見られたので、role="presentation"を追加するような設定を設けました。

tidy_clean_image

imgタグのクリーンナップを行います。廃止された属性を CSSに変換します('vspace', 'hspace', 'border')。不正な width, height を削除します(空文字・数字を含まないなど)。alt属性のない img要素に alt="" を追加します。初期値は trueです。

tidy_clean_duplicate_alt

 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>

※ 自分的には、これが結構お気に入りです。

tidy_clean_image_attrs

img要素に指定できない属性を削除します。初期値は「longdesc,name」です。longdescについては alt属性値にマージされます。

tidy_clean_block_align

ブロック要素の align属性を CSSの text-alignに置換します。対象は('p', 'div', 'dd', 'li')要素で、初期値は trueです。 trueの代わりに要素名の配列を指定することもできます。

tidy_clean_br_clear

br要素に指定された clear属性を CSSに変換します。初期値は trueです。

tidy_clean_a_href

 URLに指定できない文字列を置き換えます。初期値は('&#13;' => '', ' ' => '%20')です。

tidy_clean_a_name

a要素の name属性を id属性に置き換えます。初期値は falseです。

tidy_clean_font

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」となります。

tidy_clean_deprecated

設定で指定した廃止された要素を置き換え可能な要素に置き換えます。属性値はそのまま引き継がれます。初期値は{"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>

tidy_clean_applet

applet要素を object要素に置き換えます。初期値は trueです。

tidy_clean_dl

dl要素に必要な子要素がない時、必要な要素を補完します。dt要素もdd要素も存在しない場合、p要素に置き換えるか、内容がなければ要素自体を削除します。また、置くことのできない要素が直接置かれている時に、直近の dtdd要素にマージします。初期値は trueです。

tidy_clean_ul_ol

ulol要素に必要な子要素(li要素)がない時、必要な要素を補完します。また、置くことのできない要素が直接置かれている時に、直近の li要素にマージします。初期値は trueです。

tidy_clean_area

area要素の nohref属性(廃止)を削除し、coords内のスペースを削除します。初期値は trueです。

tidy_clean_iframe

iframe要素の frameborder属性(非推奨)を削除します。初期値は trueです。

tidy_clean_lang

lang属性の誤りを修正します。初期値は指定なしです。単に trueを指定した場合 jpja に置き換えます。他のパターンをハッシュで指定することもできます。初期値は「{"jp":"ja"}」です。

※ 他にも、様々なものが存在しました。{"jp":"ja","eん":"en","e":false,"po":"pt","eb":"en","vn":"vi","tu":"tr","cn":"zh","sp":"es"} (falseを指定したものは属性自体を削除します)

tidy_clean_empty_attrs

カンマ区切りで指定した属性の属性値が空文字であるものを削除します。初期値はありません。

tidy_clean_empty_a

href属性を含み、name属性のない a要素の要素内容が空(または空文字のみ)の時、a要素を削除します。初期値は falseです。

tidy_clean_comment

コメントノードを削除します。初期値は trueです。

tidy_clean_double_byte_space

'table', 'ul', 'ol', 'dl'要素内に直接置かれた全角スペースを半角スペースに置き換えます。初期値は trueです。

※ 結構ありました。

tidy_repair_ldquo_rdquo

「&#147;」を「“」に、「&#148;」を「”」に、「&#151;」を「—」置き換えます。初期値は falseです。

tidy_force_utf8

文字コードが UTF8のみである時に指定します。初期値は trueです。

tidy_clean_code_point

不正なコードポイントを UTF8文字に置き換えます。初期値は falseです。

tidy_html_wrap

整形後の HTMLを折り返す文字数を指定します。初期値は「0」です。

tidy_config

PHPの「tidy_parse_string」に渡す第2引数のハッシュを指定します。初期値の指定はありません。オプションについての説明は » http://api.html-tidy.org/#quick-reference  を参照ください。

プラグイン設定

その他の設定はプラグイン設定で指定します。適用する範囲を絞り込んだりすることで、意図しない変換を防ぐことができます。

  • htmltidy_exclude_petterns: 置換しない文字列パターンを改行区切りで指定します。
  • htmltidy_exclude_string: 指定した文字列を含むHTML文書を処理対象外にします。
  • htmltidy_replace_petterns: 置換したいパターンを CSVで指定します。
  • htmltidy_archive_types: 環境変数「tidy_outputfilter」指定のある時、対象のアーカイブタイプを指定します。
  • htmltidy_body_pettern: 本文部分の開始と終了を判別する文字列をカンマ区切りで指定します。例 : <main>,</main>
  • htmltidy_use_system_setting: (スペースの設定のみ) システムの設定を継承します。

グローバルモディファイア

ページ全体に適用せずに、テンプレートの特定部分だけに処理を限定できます。

  • htmltidy : 部分的に修正を適用します。環境変数「tidy_css_to_head」の設定値は反映されませんが、属性値に「2」を指定すると、パブリッシュ時に head内に styleタグを追加します。

まとめ

PowerCMS Xを利用したウェブアクセシビリティが要件に指定されているウェブサイトのリニューアルでは、リニューアル後のテンプレートを整備した後に、以下のような手順でデータ移行を行います。

  • Webスクレイピングによるデータ移行機能(HTMLImporterプラグイン)でデータを移行する。
  • AxeRunnerプラグインと、vNu(Nu Html Checker)を使い、定期的にHTMLとウェブアクセシビリティの機械チェックを実行する。
  • 結果を確認しながら、HTMLTidyプラグインの自動修復を適用できる部分を調査し、必要な設定を行う(必要に応じてHTMLTidyプラグインに機能を追加する)。
  • 最後に、人の手による修正漏れの対応と、ウェブアクセシビリティ検証、必要に応じて修正を行う。

カテゴリー:サイト制作全般 | プラグイン

投稿者:Junnama Noda

ブログ内検索

アーカイブ