二つのテーブルを一つにまとめる

はじめに

二つのテーブルを一つにまとめるxsltを考える.具体的には、以下のin.htmlの中にあるtable1とtable2をまとめて、out.htmlのtable3を作成する.table1とtable2の行を同期を取って一緒に取り出せれば良い.

<!-- in.html -->
<html>
  <table id="table1" border="1">
  <caption>table1</caption>
    <tr><td>a</td></tr>
    <tr><td>b</td></tr>
    <tr><td>c</td></tr>
  </table>

  <table id="table2" border="1">
  <caption>table2</caption>
    <tr><td>10</td></tr>
    <tr><td>20</td></tr>
    <tr><td>30</td></tr>
  </table>
</html>

<!-- out.html -->
<?xml version="1.0" encoding="utf-8"?>
<html>
  <table id="table3" border="1">
  <caption>table3</caption>
    <tr>
      <td>a</td>
      <td>10</td>
    </tr>
    <tr>
      <td>b</td>
      <td>20</td>
    </tr>
    <tr>
      <td>c</td>
      <td>30</td>
    </tr>
  </table>
</html>

in.html

table1
a
b
c
table2
10
20
30

out.html

table3
a 10
b 20
c 30

変数を使う

table1の行数を変数に保管し、table2の該当行を取り出すやり方である.分かりやすい.

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

    <xsl:output
        indent="yes"
        method="xml"
        encoding="utf-8"/>

  <xsl:template match="/">
    <html>
      <table id="table3" border="1">
        <caption>table3</caption>
        <xsl:apply-templates select="/html/table[@id='table1']/tr"/>
      </table>
    </html>
  </xsl:template>

  <xsl:template match="tr">
    <tr>
      <xsl:variable name="pos" select="position()"/> <!-- table1のカレントノードの行数を変数posに格納 -->
      <td><xsl:value-of select="td"/></td>
      <td><xsl:value-of select="//table[@id='table2']/tr[$pos]/td"/></td> <!-- table1から同じ行数を取り出す -->
    </tr>
  </xsl:template>
</xsl:stylesheet>

変数を使わない

変数を使わない書き方もできる.current関数とpreceding-siblingを使う.

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

    <xsl:output
        indent="yes"
        method="xml"
        encoding="utf-8"/>

  <xsl:template match="/">
    <html>
      <table id="table3" border="1">
        <caption>table3</caption>
          <xsl:apply-templates select="/html/table[@id='table1']/tr"/>
      </table>
    </html>
  </xsl:template>

  <xsl:template match="tr">
    <tr>
      <td><xsl:value-of select="td"/></td>
      <td><xsl:value-of select="//table[@id='table2']/tr[count(current()/preceding-sibling::*)+1]/td"/></td>
      <!-- current()が必要.コンテキストノードが//table[@id='table2']/trになるので、currnet()を付けてカレントノード//table[@id='table1']/trを明示して行数を取得する.-->
    </tr>
  </xsl:template>
</xsl:stylesheet>

実行環境

  • PC-BSD 10.3
  • Xalan Java 2.7.2

参考

Use position of current node to access value of another node