日別アーカイブ: 2016年10月25日

Table のアクセシビリティ

現在 table のアクセシビリティについての開発を行っているのですが、最近社内で XSLT 勉強会に参加しているせいか、ふと、XSLT でどうすれば自動的にアクセシビリティ対応が図れるのか気になったので検討してみたいと思います。なお、今回はアクセシビリティ関連の属性の内 scope 属性に関してのみ焦点を当てます。複雑な表の場合、headers属性の使用が推奨されていますが、現時点の私の技術力ではとても自動化などできそうにないので、今回は scope 属性に絞らせていただきました。ちなみに、scope 属性は HTML5 と同様のものだとさせて頂きます。また、XSL-FO プロセサが scope 属性に対応しているとします。

table 自体のスキーマは以下の様になっているとします。普通は、thr と tr を分けるような事はしないとおもいますが、今回は問題を簡易化にするために分けています。また、theader 内の見出しは列方向に対するもの、tbody 内の見出しは行方向に対するものとします。

table := (theader)?,(tbody)+
theader := thr
tbody := (tr)+
thr := (th)+
tr := (th)?,(td)+
th := 見出し
td := データ

また、th に対するテンプレートしか載せませんが、以下の様になっているとします。

<xsl:template match="th">
    <fo:table-cell>
      <fo:block>
        <xsl:apply-templates/>
      </fo:block>
    </fo:table-cell>
</xsl:template>

以下の様に theader が一行で、th が theader 内にしか存在しない場合だと簡単そうですね。

  <table>
    <theader>
      <thr>
        <th>見出し1</th>
        <th>見出し2</th>
        <th>見出し3</th>
      </thr>
    </theader>
    <tbody>
      <tr>
        <td>データ11</td>
        <td>データ12</td>
        <td>データ13</td>
      </tr>
      <tr>
        <td>データ21</td>
        <td>データ22</td>
        <td>データ23</td>
      </tr>
    </tbody>
  </table>

scope 属性を値 col で追加すればそれで対応完了です。後の事を考え、以下の様に <xsl:choose> を使い、th の祖先ノードを見て scope 属性を付与するということをします。

 <xsl:template match="th">
    <fo:table-cell>
      <xsl:choose>
        <xsl:when test="../../self::theader">
          <xsl:attribute name="scope">col</xsl:attribute>
        </xsl:when>
      </xsl:choose>
      <fo:block>
        <xsl:apply-templates/>
      </fo:block>
    </fo:table-cell>
</xsl:template>

次はスキーマに沿った、tbody の一列目にも th 存在する場合も考えてみます。

   <table>
    <theader>
      <thr>
        <th>見出し1</th>
        <th>見出し2</th>
        <th>見出し3</th>
      </thr>
    </theader>
    <tbody>
      <tr>
        <th>見出し11</th>
        <td>データ11</td>
        <td>データ12</td>
      </tr>
      <tr>
        <th>見出し12</th>
        <td>データ21</td>
        <td>データ22</td>
      </tr>
    </tbody>
  </table>

tbody の最初の子 th に値 row で scope 属性を与えれば良いだけなので簡単ですね。また、入力 XML がスキーマに沿わない場合に備え、<xsl:otherwise> 節を追加してエラー処理を追加するのも良いかもしれません。

 <xsl:template match="th">
    <fo:table-cell>
      <xsl:choose>
        <xsl:when test="../../self::theader">
          <xsl:attribute name="scope">col</xsl:attribute>
        </xsl:when>
        <xsl:when test="../../self::tbody and position()=1">
          <xsl:attribute name="scope">row</xsl:attribute>
        </xsl:when>
      </xsl:choose>
      <fo:block>
        <xsl:apply-templates/>
      </fo:block>
    </fo:table-cell>
</xsl:template>

今回はすごく簡単な例しか取り上げませんでしたが、次回までに私の XSLT 力が向上していたら複雑な表や、多種の表の場合を扱ってみたいと思います。恐らく多種の複雑な表を扱う場合、自動での scope 属性の付与は難しく、入力スキーマ自体に表の種類に関する情報を入れたりする必要が出てきそうです。