XSLT20 のバックアップ(No.12)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- XSLT20 へ行く。
- 1 (2016-03-24 (木) 16:35:29)
- 2 (2016-03-28 (月) 17:46:51)
- 3 (2016-04-15 (金) 15:54:16)
- 4 (2016-05-09 (月) 15:49:54)
- 5 (2016-05-11 (水) 18:29:54)
- 6 (2016-05-16 (月) 17:02:14)
- 7 (2016-05-17 (火) 15:03:21)
- 8 (2016-05-23 (月) 15:20:18)
- 9 (2016-05-24 (火) 16:07:13)
- 10 (2016-05-24 (火) 19:20:06)
- 11 (2016-05-25 (水) 15:56:42)
- 12 (2016-06-07 (火) 18:12:55)
- 13 (2016-07-28 (木) 14:11:20)
- 14 (2016-07-29 (金) 13:01:28)
- 15 (2016-08-01 (月) 13:51:06)
- 16 (2016-08-04 (木) 14:20:25)
- 17 (2016-08-12 (金) 14:27:43)
- 18 (2016-08-12 (金) 15:35:29)
- 19 (2017-10-13 (金) 15:46:37)
- 20 (2017-12-07 (木) 18:13:41)
- 21 (2017-12-15 (金) 14:21:36)
- 22 (2018-10-02 (火) 13:51:51)
- title: XSL Transformations (XSLT) Version 2.0 description: XSL Transformations (XSLT) Version 2.0 に関するメモ書き author: aterai pubdate: 2016-03-24
概要
XSL Transformations (XSLT) Version 2.0
関連のメモ書きです。
XSL Transformations (XSLT) Version 2.0 とは
関数など
fn:doc-avalable()
@echo off
setlocal
set SRC=C:/tmp/aaa/word/document.xml
set DST=C:/output/aaa/xxx.xml
set LIB=C:/lib/saxon-9.1.0.8.jar
set SAXON=net.sf.saxon.Transform
set XSLT=C:/xslt/docx2xxx.xsl
"%JAVA_HOME%\bin\java" -cp "%LIB%" %SAXON% -s:"%SRC%" -xsl:"%XSLT%" -o:"%DST%"
<!-- C:/tmp/aaa/word/numbering.xml が存在するかをチェックしたい -->
<xsl:if test="fn:doc-available(fn:replace(fn:base-uri(),'document\.xml$','numbering.xml'))">
<xsl:variable name="numbering" select="fn:document('numbering.xml',/)/w:numbering" />
</xsl:if>
fn:document('numbering.xml',/)
のように第二引数を指定して入力ファイル相対パスでfn:doc-available
を使用することは出来ないfn:base-uri()
->C:/tmp/aaa/word/document.xml
fn:resolve-uri('')
->C:/xslt/docx2xxx.xsl
xsl:analyze-string
docx
のw:lvlText
のフォーマット(例えば%1.%2.%3
)に従って、実際の段落番号文字列(例えば、1.5.10
)に変換する場合、xsl:analyze-string
が便利。
<!-- w:lvlRestartの処理などは省略 -->
<xsl:variable name="numberText">
<xsl:analyze-string select="$lvl/w:lvlText/@w:val" regex="%\d">
<xsl:matching-substring>
<xsl:variable name="pos" select="number(replace(.,'%',''))" />
<xsl:variable name="i" select="$pos - 1" />
<xsl:variable name="ii" select="$i - 1" />
<xsl:variable name="parentList" select="$list[(w:pPr/w:numPr/w:ilvl and w:pPr/w:numPr/w:ilvl/@w:val=$ii) or ($ii=0 and not(w:pPr/w:numPr/w:ilvl))]" />
<xsl:variable name="pstl" select="if(empty($parentList)) then '' else $parentList[1]/w:pPr/w:pStyle/@w:val" />
<xsl:variable name="next" select="if(empty($psList) or empty($pstl)) then () else index-of($psList,$pstl)" />
<xsl:variable name="list2" select="if(empty($next)) then $list else subsequence($list,$next[last()])" />
<xsl:value-of select="fn:count($list2[(w:pPr/w:numPr/w:ilvl and w:pPr/w:numPr/w:ilvl/@w:val=$i) or ($i=0 and w:pPr/w:numPr and not(w:pPr/w:numPr/w:ilvl))])" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
to演算子
<xsl:for-each select="1 to $gridBefore">
のように、指定した回数でループすることが可能で、以下の例ではw:trPr/w:gridBefore
で指定された数だけ空のtd
を作成している。
<xsl:template match="w:tr">
<tr>
<xsl:variable name="gridBefore" as="xs:integer" select="if(w:trPr/w:gridBefore) then w:trPr/w:gridBefore/@w:val else 0" />
<xsl:if test="$gridBefore > 0">
<xsl:for-each select="1 to $gridBefore">
<td></td>
</xsl:for-each>
</xsl:if>
<xsl:apply-templates select="w:tc[not(w:tcPr/w:vMerge) or w:tcPr/w:vMerge/@w:val='restart']" />
<tr>
</xsl:template>
- XSLT by Example: Obtain position() from “for” expression in Xpath 2のように、
<xsl:variable name="aaa" select="for $i in (1 to 9) return $i" />
で<xsl:variable name="bbb" as="xs:integer*" select="(1,2,3,4,5,6,7,8,9)" />
と同じシーケンスが作成可能
<xsl:variable name="aaa" select="for $i in (1 to 9) return $i" />
<xsl:variable name="bbb" as="xs:integer*" select="(1,2,3,4,5,6,7,8,9)" />
<xsl:value-of select="deep-equal($aaa,$bbb)" /> <!-- true -->
<xsl:value-of select="for $i in (0 to 2) return $i" />
は、(0,1,2)
<xsl:value-of select="for $i in (3 to 1) return $i" />
は、()
<xsl:value-of select="for $i in reverse(1 to 3) return $i" />
は、(3,2,1)
<xsl:value-of select="for $i in (1 to 1) return $i" />
は、(1)
<xsl:value-of select="for $i in (-1 to 1) return $i" />
は、(-1,0,1)
<xsl:value-of select="for $i in (1, 3 to 5, 7) return $i" />
は、(1,3,4,5,7)
for~in~return 式
for~in~return
式は、二重ループなども可能。
<xsl:function as="xs:string*" name="myfn:get-merge-cells">
<xsl:param name="ref" as="xs:string" />
<xsl:variable name="a" as="xs:integer*">
<xsl:analyze-string select="$ref" regex="([A-Z]+)([0-9]+):([A-Z]+)([0-9]+)">
<xsl:matching-substring>
<xsl:sequence select="myfn:column-index(regex-group(1))" />
<xsl:sequence select="xs:integer(regex-group(2))" />
<xsl:sequence select="myfn:column-index(regex-group(3))" />
<xsl:sequence select="xs:integer(regex-group(4))" />
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<!-- xsl:sequence select="remove(for $ri in ($a[2] to $a[4]) return for $ci in ($a[1] to $a[3]) return concat(myfn:column-label($ci),$ri), 1)" / -->
<xsl:sequence select="remove(for $ri in ($a[2] to $a[4]), $ci in ($a[1] to $a[3]) return concat(myfn:column-label($ci),$ri), 1)" />
</xsl:function>
myfn:get-merge-cells('A18:D20')
は、(B18, C18, D18, A19, B19, C19, D19, A20, B20, C20, D20)
fn:codepoints-to-string, fn:string-to-codepoints
Excel
などの列名(アルファベット26
進数bijective base-26
の文字列)を10
進数の列番号に変換する<xsl:value-of select="myfn:column-index('AA')" />
は、27
<xsl:value-of select="myfn:column-index('XFD')" />
は、16384
<!-- 関数: アルファベット26進数(bijective base-26)の文字列を10進数のxs:integerに変換 -->
<!-- べき乗が計算できない?ので、あらかじめ用意する。最大列はXFD(16384)なので、26^3(17576)は不要 -->
<xsl:variable name="power" as="xs:integer+" select="(1, 26, 676)" />
<!-- xsl:variable name="AtoZ" as="xs:string+" select="('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')" / -->
<xsl:variable name="AtoZ" as="xs:string+" select="for $i in (0 to 26 - 1) return codepoints-to-string(string-to-codepoints('A') + $i)" />
<xsl:function as="xs:integer" name="myfn:column-index">
<xsl:param name="str" as="xs:string" />
<xsl:variable name="len" select="fn:string-length($str)" /> <!-- 最大3桁 -->
<xsl:value-of select="sum(for $i in (1 to $len) return index-of($AtoZ, substring($str, $i, 1)) * $power[$len - $i + 1])" />
</xsl:function>
- 列番号の数値を列名に変換
<xsl:value-of select="myfn:column-label(702)" />
は、ZZ
<xsl:value-of select="myfn:column-label(703)" />
は、AAA
<xsl:function as="xs:string" name="myfn:column-label">
<xsl:param name="num" as="xs:integer" />
<xsl:variable name="cpa" as="xs:integer" select="string-to-codepoints('A')" />
<xsl:variable name="dv3" as="xs:integer" select="($num - 26 - 1) idiv 676" />
<xsl:variable name="st3" as="xs:string" select="if($dv3 != 0) then codepoints-to-string($cpa + $dv3 - 1) else ''" />
<xsl:variable name="md3" as="xs:integer" select="$num - ($dv3 * 676)" />
<xsl:variable name="dv2" as="xs:integer" select="($md3 - 1) idiv 26" />
<xsl:variable name="st2" as="xs:string" select="if($dv2 != 0) then codepoints-to-string($cpa + $dv2 - 1) else ''" />
<xsl:variable name="md2" as="xs:integer" select="$md3 - ($dv2 * 26)" />
<xsl:variable name="st1" as="xs:string" select="codepoints-to-string($cpa + $md2 - 1)" />
<xsl:value-of select="concat($st3,$st2,$st1)" />
</xsl:function>