XMLマスターへの道
〜「XMLマスター:ベーシック」試験対策〜

第11回 XSLTで必須の制御命令を覚える

内藤一彦
NRIラーニングネットワーク株式会社
2003/11/27

 前回「第10回 XSLTの基本構造を理解する」では、XML文書を変換するXSLTの基本構造について紹介しました。今回は、前回の内容を踏まえて、より多くのパターンに応用できるXSLT命令について紹介します。前回で予習問題として下記の問題を出題しておきました。この問題を解くための解説をした後、解答を示します。

今回の問題

(Q1) 次のような学生一覧のXML文書があるときに、学年・クラス・出席番号の順でソートを行い処理したい。このときの、ソートの記述方法として正しいのはどれでしょう。

学生一覧XML
<Students>
  <Student grade="2" class="A" no="16" >Naito</Student>
  <Student grade="1" class="B" no="11" >Ito</Student>
  <Student grade="2" class="A" no="28" >Saito</Student>
  <Student grade="2" class="A" no="1" >Bito</Student>
  <Student grade="2" class="C" no="15" >Kato</Student>
</Students>

(a)
<xsl:for-each select="Student" order="@grade"
 order="@class" order="@no">
    繰り返す処理内容
</xsl:for-each>

(b)
<xsl:for-each select="Student">
  <xsl:sort select="@grade" >
    <xsl:sort  select="@class">
      <xsl:sort  select="@no">
        繰り返す処理内容
      </xsl:sort>
    </xsl:sort>
  </xsl:sort>
</xsl:for-each>

(c)
<xsl:sort select="@grade" >
  <xsl:sort  select="@class">
    <xsl:sort  select="@no">
      <xsl:for-each select="Student">
        繰り返す処理内容
      </xsl:for-each>
    </xsl:sort>
  </xsl:sort>
</xsl:sort>

(d)
<xsl:for-each select="Student">
  <xsl:sort select="@grade" />
  <xsl:sort  select="@class" />
  <xsl:sort  select="@no" />
  繰り返す処理内容
</xsl:for-each>

(Q2) 組み込みテンプレートとして正しいものをすべて選択してください。

(a)
<xsl:template  match="*|/">
  <xsl:apply-templates />
</xsl:template>

(b)
<xsl:template  match="text()|@*">
  <xsl:value-of  select="."/>
</xsl:template>

(c)
<xsl:template  
 match="processinginstruction()|comment()" />

(d)
<xsl:template  match="node()" />

 今回は、この問題に解答するうえで必要となる下記の内容について解説します。

  • さまざまな制御命令
    • 繰り返し(xsl:for-each)
    • 条件付き処理(xsl:if)
    • 条件分岐(xsl:choose)
    • ソート(xsl:sort)
  • 新しいノードの作成
    • 要素ノード(xsl:element)/属性ノードの作成(xsl:attribute)
  • 出力指定(xsl:output)
  • 組み込みテンプレート

 今回は、命令の書き方が中心となります。非常によく使われるものをピックアップしていますので、実際にサンプルを動かしたり、自分で作って検証してください。

さまざまな制御命令

繰り返し(xsl:for-each)

 xsl:for-eachは指定されたノードを取り出しながら処理を繰り返します。そして取り出すノードがなくなると、繰り返しから抜けます。

xsl:for-eachの構文

<xsl:for-each  select="ノード式">
    繰り返す処理内容
</xsl:for-each>


<?xml version="1.0" encoding="Shift_JIS" ?>

<EMPLOYEES>
  <EMPLOYEE>
    <Name>Kazuhiko Naito</Name>
  </EMPLOYEE>
  <EMPLOYEE >
    <Name>Masahiko Kondo</Name>
  </EMPLOYEE>
  <EMPLOYEE>
    <Name>Reiko Sato</Name>
  </EMPLOYEE>
  <EMPLOYEE>
    <Name>Masao Ito</Name>
  </EMPLOYEE>
</EMPLOYEES>
リスト1 変換元のXML文書(for-each.xml

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

<xsl:template match="/" >
<HTML>
  <BODY>
    <TABLE BORDER="1">
      <xsl:for-each select="/EMPLOYEES/EMPLOYEE">
        <TR><TD><xsl:value-of select="Name" /></TD></TR>
      </xsl:for-each>

    </TABLE>
  </BODY>
</HTML>
</xsl:template>

</xsl:stylesheet>
リスト2 XSLTスタイルシート文書(for-each.xsl

 上記のリスト1、for-each.xmlの2行目に

<?xml-stylesheet type="text/xsl" href="for-each.xsl" ?>

を挿入し、for-each.xmlをIE 6.0で開くと次のようになります。

図1 IE 6.0でfor-each.xmlを表示

参考
 このサンプルではxsl:for-eachを使用してそれぞれのEMPLOYEEを処理していますが、xsl:apply-templatesを使用しても同様の結果を得ることができます。

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

<xsl:template match="/" >
<HTML>
  <BODY>
    <TABLE BORDER="1">
      <xsl:apply-templates select="/EMPLOYEES/EMPLOYEE"/>
     </TABLE>
  </BODY>
</HTML>
</xsl:template>
<xsl:template match="EMPLOYEE">
    <TR><TD><xsl:value-of select="Name" /></TD></TR>
</xsl:template>

</xsl:stylesheet>
リスト3 xsl:apply-templatesを使用するスクリプト

条件付き処理(xsl:if)

 xsl:ifは条件を評価して、条件が成り立った場合にのみ処理を行います。一般的なプログラム言語では「if 〜then〜else〜」というように、条件が成り立った場合と成り立たなかった場合の処理を記述できますが、xsl:ifでは成り立った場合の処理のみ記述します

xsl:ifの構文

<xsl:if  test="条件">
    条件が成り立った場合の内容
</xsl:if>

 test属性で指定する条件には、trueかfalseを返す式を記述します。また、条件式の中で「<」「>」「'」「"」「&」など特殊記号を使用する場合、そのまま使うと誤って解釈されたりエラーが発生する可能性があるので、定義済み実体を利用します(「第4回 すべてのXML文書は整形式である 表3 定義済み実体」参照)。

例えば、

「salary<300000」という条件を記述したいのであれば

test="salary&lt;300000"

「dept="sales"」(dept要素がsalesという文字列)であれば、

test="dept='sales'"

または

test="dept=&apos;sales&apos;"

とします。

条件分岐(xsl:choose)

 xsl:chooseはxsl:whenやxsl:otherwiseと組み合わせて使用します。

xsl:chooseの構文

<xsl:choose>
  <xsl:when  test="条件1">
    条件1が成り立った場合の内容
  </xsl:when>
  <xsl:when  test="条件2">
    条件2が成り立った場合の内容
  </xsl:when>
      :
 <xsl:otherwise>
    いずれの条件も成り立たなかった場合の内容
  </xsl:otherwise>
</xsl:choose>

  • xsl:when:1つ以上記述する。記述されている順にtest属性が評価され、条件が成り立った場所の処理を行う
  • xsl:otherwise:最後に1つだけ記述するか、記述しなくても構わない。いずれのxsl:whenの条件も成り立たなかった場合に処理が行われる

 ここで、xsl:ifとxsl:chooseを使用している例を紹介します。

<?xml version="1.0" encoding="Shift_JIS" ?>
<EMPLOYEES>
  <EMPLOYEE  empid="A001">
    <Name>Kazuhiko Naito</Name>
    <Dept >Education</Dept>
    <Salary>200000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="B002">
    <Name>Masahiko Kondo</Name>
    <Dept >Sales</Dept>
    <Salary>300000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="C003">
    <Name>Reiko Sato</Name>
    <Dept >Education</Dept>
    <Salary>400000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="D004">
    <Name>Masao Ito</Name>
    <Dept >Sales</Dept>
    <Salary>500000</Salary>
  </EMPLOYEE>
</EMPLOYEES>
リスト4 変換元のXML文書(employee.xml

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

<xsl:template match="/" >
<HTML>
  <BODY>
Over 400000 Salary<BR/>
=================<BR/>
    <xsl:for-each select="/EMPLOYEES/EMPLOYEE">
      <xsl:if test="Salary>=400000">  ←xsl:if
        <xsl:value-of select="Name" /><BR/>
      </xsl:if>
    </xsl:for-each>
<BR/><BR/>

    <xsl:apply-templates select="/EMPLOYEES/EMPLOYEE"/>

  </BODY>
</HTML>
</xsl:template>

<xsl:template match="EMPLOYEE" >
  <xsl:choose>  ←xsl:choose
    <xsl:when test="Salary>=500000">
      <xsl:value-of select="Name"/>[Over 500000]<BR/>
    </xsl:when>
    <xsl:when test="Salary>=400000">
      <xsl:value-of select="Name"/>[Between 400000 and 500000]<BR/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="Name"/>[Under 400000] <BR/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>
リスト5 XSLTスタイルシート文書(if-choose.xsl

 上記リスト4、employee.xmlの2行目に

<?xml-stylesheet type="text/xsl" href="if-choose.xsl" ?>

を挿入し、employee.xmlをIE 6.0で開くと次のようになります。

図2 IE 6.0でemployee.xmlを表示

 xsl:if の部分では、Salaryが400000以上(Salary>=400000)であれば、社員の名前を表示するようにしています。

また、xsl:chooseでは、

  • Salaryが500000以上ならば[Over 500000]
  • Salaryが400000以上500000未満ならば[Between 400000 and 500000]
  • それ以外(Salaryが400000未満)ならば[Under 400000]

 と表示されるようにしています。

ソート(xsl:sort)

 xsl:sortを使うとノードを取り出すときにソートを行います。記述方法は難しくありませんが、使い方に注意が必要です。

xsl:sortの構文

<xsl:sort select="ノード" data-type="データタイプ" order="並び順" />

  • select属性:ソートキーとなるノードを指定
  • data-type属性:text (文字としてソート)、number(数値としてソート)。省略時はtextが採用される
  • order属性:ascending (昇順)、descending(降順)。省略時はascendingが採用される

 さて、これをどこに記述するかです。記述できる場所は、xsl:apply-templates要素かxsl:for-each要素の中だけです。ともに、xsl:sortを使用していない場合にはノードの処理順序はそのままデータの記述どおりの順序となります。

 ですから、前述のサンプル(for-each.xslやif-choose.xsl)ではEMPLOYEEの処理は記述されている順番どおりとなっています。これにソートを加えたいのであれば、次のようにxsl:sortを加えます。これにより、ソートを行った結果の順序でノードの処理を行ってくれます。

<xsl:template match="/" >
<HTML>
  <BODY>
    <TABLE BORDER="1">
      <xsl:for-each select="/EMPLOYEES/EMPLOYEE">
        <xsl:sort select="Salary" data-type="number"
                 order="descending" />

        <xsl:if test="Salary>=400000">
             :(途中省略)

    <xsl:apply-templates select="/EMPLOYEES/EMPLOYEE">
      <xsl:sort select="Salary" data-type="number"
               order="descending" />

    </xsl:apply-templates>
             :(以下省略)
リスト6 xsl:sortを加えたスクリプト

 また、xsl:sortを並べて記述すると複次ソートの指定となりますので、入れ子にせずに記述します

 前回の予習問題の解答となりますが、次のように学生名簿で、学年・組・出席番号の順で複次ソートを行うことができます。

<?xml version="1.0" encoding="Shift_JIS" ?>
<Students>
  <Student grade="2" class="A" no="16" >Naito</Student>
  <Student grade="1" class="B" no="11" >Ito</Student>
  <Student grade="2" class="A" no="28" >Saito</Student>
  <Student grade="2" class="A" no="1" >Bito</Student>
  <Student grade="2" class="C" no="15" >Kato</Student>
</Students>
リスト7 変換元のXML文書(sort.xml

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

<xsl:template match="/" >
<HTML>
  <BODY>
    <TABLE BORDER="1">
      <xsl:for-each select="/Students/Student">
        <xsl:sort select="@grade" />
        <xsl:sort select="@class" />
        <xsl:sort select="@no" />
        <TR><TD><xsl:value-of select="@grade" /></TD>
          <TD><xsl:value-of select="@class" /></TD>
          <TD><xsl:value-of select="@no" /></TD>
          <TD><xsl:value-of select="." /></TD></TR>
      </xsl:for-each>
    </TABLE>
  </BODY>
</HTML>
</xsl:template>

</xsl:stylesheet>
リスト8 XSLTスタイルシート文書(sort.xsl

 上記のリスト7のsort.xmlの2行目に

<?xml-stylesheet type="text/xsl" href="sort.xsl" ?>

を挿入し、sort.xmlをIE 6.0で開くと次のようになります。

図3 IE 6.0でsort.xmlを表示

ノードの作成

要素ノード(xsl:element)/属性ノードの作成(xsl:attribute)

 ここまではHTMLやほかのXML形式に変換する場合、スタイルシートの中にタグを直接記述してきましたが、専用のXSLT命令を使って生成することもできます。

xsl:elementの構文

<xsl:element  name="要素名">
  要素の値、子要素、属性
</xsl:element>


xsl:attributeの構文

<xsl:attribute  name="属性名">
  属性の値
</xsl:attribute>


<?xml version="1.0" encoding="Shift_JIS" ?>
<EMPLOYEE>
    <ID>A001</ID>
    <Name>Kazuhiko Naito</Name>
</EMPLOYEE>
リスト9 変換元のXML文書(employee2.xml

 このXMLを次のような別のXML構造に変換します。

図4 XML構造を変更する

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

<xsl:template match="/" >
  <xsl:element name="EMP">
    <xsl:attribute name="id">
      <xsl:value-of select="/EMPLOYEE/ID" />
    </xsl:attribute>
    <xsl:value-of select="/EMPLOYEE/Name" />
  </xsl:element>
</xsl:template>
</xsl:stylesheet>
リスト10 XSLTスタイルシート文書(elemTrans.xsl

 上記リスト9のemployee2.xmlの2行目に

<?xml-stylesheet type="text/xsl" href="elemTrans.xsl" ?>

を挿入し、employee2.xmlをIE 6.0で開きます。その後、ウィンドウ内で右クリックしメニューから「View XSL Output」を実行します(「Viewing XSLT Output」ツールは、第5回第10回の記事中で紹介しています)。

図5 View XSL Output での表示内容

 作成する要素に「要素の値」と「属性」を持たせる場合、注意する点があります。それは、属性を作成する要素には、すでに子ノードがあってはいけないということです。従って、サンプルで記述している「属性の作成」と「要素の値の作成」の順番が逆になるとエラーが発生します。必ず、属性が作成されてから要素の値や子要素を作成するようにしなければなりません。

<xsl:element name="EMP">
  <xsl:attribute name="id">  ←属性の作成
    <xsl:value-of select="/EMPLOYEE/ID" />
  </xsl:attribute>
  <xsl:value-of select="/EMPLOYEE/Name" /> ←EMP要素の値の作成
</xsl:element>
リスト11 正しい記述

<xsl:element name="EMP">
  <xsl:value-of select="/EMPLOYEE/Name" /> ←EMP要素の値の作成
  <xsl:attribute name="id">  ←属性の作成
    <xsl:value-of select="/EMPLOYEE/ID" />
  </xsl:attribute>
</xsl:element>
リスト12 エラーが発生

出力指定(xsl:output)

 xsl:outputを使用すると変換によって得られるドキュメントの形式やインデントの有無などを指定できます。また、xsl:outputはトップレベル要素であるため、必ずルート要素であるxsl:stylesheetの直系の子として記述します。

xsl:outputの構文

<xsl:output
       method="出力ドキュメント形式"
       そのほかの属性
/>

method属性:xml、html、textを指定

method="html"の動作

 HTMLに変換する場合、使用したいHTMLタグをXSLTスタイルシートの中で直接記述することができます。ただし、HRやBRなどを使用する場合、注意が必要です。これらのタグはHTMLでは、終了タグは必要としません。

<xsl:template match="/" >
<HTML><BODY>
      :
 <BR>
<BR>
リスト13 エラーが発生

 しかし、リスト13のように、HTMLのルールに従ってBRタグを記述するとエラーが発生します。なぜなら、HTMLタグという以前にこのXSLTファイルはXML形式でなければならないので、開始タグに対応する終了タグが必要となるからです。エラーにならないためには、次のように記述する必要があります。

<xsl:template match="/" >
<HTML><BODY>
      :
 <BR/>
<BR/>
リスト14 正しいHTMLタグの記述

 このような場合に、method="html"が指定されていると、変換時にHTML形式を考慮して終了タグを自動的に削除して出力します。

 method属性が省略されている場合、出力するドキュメントのルート要素が、<HTML>(大文字・小文字を問わない)で始まっている場合には、自動的にmethod="html"を採用します。それ以外の場合には、method="xml"を採用します。

method="text"の動作

 この場合、すべてのテキストノードのみが出力されます。従って、出力されるのは要素の値部分のみです。

 そのほかの属性としては、次のようなものがあります。

  • encoding属性:出力ドキュメントの文字エンコーディング方式
  • omit-xml-declaration属性:「yes」または「no」。XML宣言、テキスト宣言を出力するかしないか
  • indent属性:「yes」または「no」。インデントするかしないか

組み込みテンプレート

 XSLTではあらかじめ組み込まれているテンプレートとして次の3種類があります。これらは、テンプレートの呼び出し方法が間違っていたなどの理由で、ユーザーが記述していないテンプレートの呼び出しを行った場合に、呼び出されます。

  1. ルートノードまたはすべての要素ノード用のテンプレート(すべての子ノードに対してテンプレート呼び出しを実行する)

    <xsl:template match="*|/" >
       <xsl:apply-templates />
    </xsl:template>


  2. すべてのテキストノードまたはすべての属性ノード用のテンプレート(自分の値を取得する)

    <xsl:template match="text()|@*" >
       <xsl:value-of  select="." />
    </xsl:template>


  3. すべてのXSLT処理命令ノードまたはすべてのコメントノード用のテンプレート(何もしない)

    <xsl:template match="processing-instruction()|comment()" />


 極端な例ですが、次のようなXSLTスタイルシートでもエラーが発生することなく変換が行われます(すべての要素・属性の値が出力されます)。

<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">

</xsl:stylesheet>
リスト15 すべての要素・属性の値が出力されるスクリプト


今回の問題の解答

 それでは、予習問題の解答を解説いたします。

(Q1) 次のような学生一覧のXML文書があるときに、学年・クラス・出席番号の順でソートを行い処理したい。このときの、ソートの記述方法として正しいのはどれでしょう。

 答えは、(d)です。

複次ソートを行う場合、

<xsl:sort select="1次ソートキー" />
<xsl:sort select="2次ソートキー" />
<xsl:sort select="3次ソートキー" />

というように、xsl:sortを記述していきます。

 「さまざまな制御命令」の「ソート(xsl:sort)」で、この問題をサンプルに取り上げていますので、もう一度確認しておきましょう。

(Q2) 組み込みテンプレートとして正しいものをすべて選択してください。

 答えは、(a)、(b)、(c)です。

 組み込みテンプレートとしては、3種類あります。それらが、この問題での解答となる3つです。記述されていないテンプレートが誤って呼び出された場合など、これらのテンプレートが呼び出され処理されます。「組み込みテンプレート」で解説していますので、もう一度確認しておきましょう。node() (すべてのノード)に対するテンプレートは用意されていません。

次回の予習問題

 次回のために予習問題を掲載します。次回はXPathです。XSLTと非常に密接な関係にあり、XSLTにはなくてはならない機能です。

予習問題
共通のXMLドキュメント
<?xml version="1.0" encoding="Shift_JIS" ?>
<EMPLOYEES>
  <EMPLOYEE  empid="A001">
    <Name>Kazuhiko Naito</Name>
    <Dept >Education</Dept>
    <Salary>200000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="B002">
    <Name>Masahiko Kondo</Name>
    <Dept >Sales</Dept>
    <Salary>300000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="C003">
    <Name>Reiko Sato</Name>
    <Dept >Education</Dept>
    <Salary>400000</Salary>
  </EMPLOYEE>
  <EMPLOYEE  empid="D004">
    <Name>Masao Ito</Name>
    <Dept >Sales</Dept>
    <Salary>500000</Salary>
  </EMPLOYEE>
</EMPLOYEES>

共通のXSLTテンプレート部分
<xsl:template match="/" >
<HTML>  <BODY>
Over 400000 Salary<BR/>
=================<BR/>
     <xsl:apply-templates select=" (1) "/>

  </BODY></HTML>
</xsl:template>

<xsl:template match="EMPLOYEE" >
      <xsl:value-of select="Name"/>
      <xsl:value-of select="Salary"/> <BR/>
 </xsl:template>

</xsl:stylesheet>

(Q1) 共通のXMLからSalaryが400000以上の社員情報を取得したい。共通のXSLTのテンプレートの(1)に入れるべき記述として正しいものを選択してください。

(a) /EMPLOYEES/EMPLOYEE(Salary &gt;=400000)
(b) /EMPLOYEES/EMPLOYEE[Salary&gt;=400000]
(c) /EMPLOYEES/EMPLOYEE/Salary&gt;=400000
(d) /EMPLOYEES/EMPLOYEE/[Salary&gt;=400000]

(Q2) 共通のXMLのEMPLOYEEのうち、先頭の2件(データの記述順)の社員情報を取得したい。共通のXSLTのテンプレートの(1)に入れるべき記述として正しいものを選択してください。

(a) /EMPLOYEES/EMPLOYEE[&lt;3]
(b) /EMPLOYEES/EMPLOYEE[EMPLOYEE&lt;3]
(c) /EMPLOYEES/EMPLOYEE[position()&lt;3]
(d) /EMPLOYEES/EMPLOYEE[position(&lt;3)]

まとめノート:XSLTで必須の制御命令を覚える

○今回の試験対策のポイント

  • さまざまな制御命令
    • 繰り返し(xsl:for-each)
    • 条件付処理(xsl:if)
    • 条件分岐(xsl:choose)
    • ソート(xsl:sort)
  • 新しいノードの作成
    • 要素ノード(xsl:element)/属性ノードの作成(xsl:attribute)
  • 出力指定(xsl:output)
  • 組み込みテンプレート

○今回の学習内容で出題範囲となる仕様

○今回の学習内容で実機確認を行うときに役立つフリーツール

○今回の学習内容で参考になる@ITの記事

○今回の学習内容で参考になるXML用語集 @IT XML用語事典より)

(12)XPathによるノードの指定法を理解する

Index
連載:XMLマスターへの道
  (1)XMLマスター:ベーシック試験のレベルは?
  (2)XMLの概要と起源、関連規格
  (3)XML文書の要素、エンコーディング、宣言
  (4)すべてのXM文書は整形式である
  (5)valid XMLとDTDの関係
  (6)模擬問題:XMLの基本
  (7)模擬問題:W3C XML Schema
  (8)模擬問題:DOM
  (9)DTDの実体宣言と記法宣言
  (10)XSLTの基本構造を理解する
(11)XSLTで必須の制御命令を覚える
  (12)XPathによるノードの指定法を理解する
  (13)名前空間を理解しDOMの概要をつかむ
  (14)XML Schemaを利用したスキーマ定義
  (最終回)XML Schema―型の再利用と名前空間


連載:XMLマスターへの道


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間