私はあなたのすべての質問に答えません。StackOverflow には少し多すぎます。私がすることは、あなたの質問の核となる部分に答えることです (最初の列)。これは、完全な答えを得るために外挿するのに十分なはずです. 私の答えから推測するのに問題がある場合は、問題の未解決の部分を小さなタスクに分割し、もちろん、自分でうまく試した後、それぞれに個別の SO 質問を投稿してください。
この入力文書は...(形成エラーを修正し、最後のliのケースを処理しないために、あなたのものとは少し異なります)
<DIV>
<ul>
<li>fr0.1.1 : en1.1.1</li>
<li>fr0.2.1 : en1.2.1</li>
<li>fr0.4.1 : en1.3.1</li>
<li>fr0.6.1 : en1.4.1</li>
<li>fr0.5.1 : en1.5.1</li>
<li>fr0.7.1 : en1.5.1</li>
</ul>
</DIV>
... この XSLT 2.0 スタイルシートに適用すると ...
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:so="http://stackoverflow.com/questions/17776650"
exclude-result-prefixes="xsl xs fn so">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:function name="so:middle-number" as="xs:integer">
<xsl:param name="dotted-text" as="xs:string" />
<xsl:sequence select="fn:replace( $dotted-text, 'fr0\.(\d+)\.1.*', '$1') cast as xs:integer" />
</xsl:function>
<xsl:function name="so:delta" as="xs:integer">
<!-- Difference between this node and the previous.
Count the first node as having difference = 1 . -->
<xsl:param name="li" as="element()" />
<xsl:sequence select="
if ($li/preceding-sibling::li) then
so:middle-number($li/text()) - so:middle-number($li/preceding-sibling::li[1]/text())
else
1" />
</xsl:function>
<xsl:function name="so:in-between" as="xs:integer*">
<xsl:param name="lower-bound" as="xs:integer" />
<xsl:param name="upper-bound" as="xs:integer" />
<xsl:variable name="diff" select="$upper-bound - $lower-bound" />
<xsl:choose>
<xsl:when test="$diff eq 0">
<xsl:sequence select="$lower-bound" />
</xsl:when>
<xsl:when test="$diff eq 1">
<xsl:sequence select="$lower-bound, $lower-bound+1" />
</xsl:when>
<xsl:when test="($diff ge 2)">
<xsl:variable name="half-way" select="fn:round( $lower-bound + ($diff div 2))" />
<xsl:sequence select="so:in-between($lower-bound, $half-way) , so:in-between( $half-way+1, $upper-bound)" />
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:function>
<xsl:template match="/*/ul">
<xsl:variable name="groups">
<xsl:for-each-group select="li" group-adjacent="so:delta(.)">
<so:group>
<so:start><xsl:value-of select="so:middle-number( current-group()[1 ]/text())" /></so:start>
<so:end> <xsl:value-of select="so:middle-number( current-group()[last()]/text())" /> </so:end>
</so:group>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$groups" />
</xsl:template>
<xsl:template match="so:group[1]" />
<xsl:template match="so:group">
<xsl:variable name="this" select="so:start/text() cast as xs:integer" as="xs:integer" />
<xsl:variable name="prev" select="preceding-sibling::so:group[1]/so:end/text() cast as xs:integer" as="xs:integer" />
<xsl:for-each select="for $x in so:in-between( $prev + 1, $this - 1) return $x">
<td><xsl:value-of select="concat('0.',.,'.1')" /></td>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...結果が得られます...
<td>0.3.1</td>
<td>0.6.1</td>
.. これは、2 つの存在しない li 値です。
お持ち帰りポイント
xsl:for-each-group/@group-adjacent 命令を使用して、1 つの li ノードの値とその前のノードの間のデルタでグループ化できます。これにより、連続したノードのグループが得られます。したがって、あるグループの終わりと次のグループの始まりの間の差をスパンするだけで、すべての欠落した値が得られます。これにより、最初の列が得られます。
他の列にも同様の手法を使用します。
アップデート
so:in between() 関数が必要ないことに気付きました。単純に演算子を使用できますto
。申し訳ありません。演算子に変更するとto
、スタイルシートが大幅に簡素化されます。
更新 2
これがto
バージョンです...私はそれが十分に小さいと思います!
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:so="http://stackoverflow.com/questions/17776650"
exclude-result-prefixes="xsl xs fn so">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:function name="so:middle-number" as="xs:integer">
<xsl:param name="dotted-text" as="xs:string" />
<xsl:sequence select="fn:replace( $dotted-text, 'fr0\.(\d+)\.1.*', '$1') cast as xs:integer" />
</xsl:function>
<xsl:function name="so:delta" as="xs:integer">
<!-- Difference between this node and the previous.
Count the first node as having difference = 1 . -->
<xsl:param name="li" as="element()" />
<xsl:sequence select="
if ($li/preceding-sibling::li) then
so:middle-number($li/text()) - so:middle-number($li/preceding-sibling::li[1]/text())
else
1" />
</xsl:function>
<xsl:template match="/*/ul">
<xsl:variable name="groups">
<xsl:for-each-group select="li" group-adjacent="so:delta(.)">
<so:group>
<so:start><xsl:value-of select="so:middle-number( current-group()[1 ]/text())" /></so:start>
<so:end> <xsl:value-of select="so:middle-number( current-group()[last()]/text())" /> </so:end>
</so:group>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$groups" />
</xsl:template>
<xsl:template match="so:group[1]" />
<xsl:template match="so:group">
<xsl:variable name="this" select="so:start/text() cast as xs:integer" as="xs:integer" />
<xsl:variable name="prev" select="preceding-sibling::so:group[1]/so:end/text() cast as xs:integer" as="xs:integer" />
<xsl:for-each select="for $x in $prev + 1 to $this - 1 return $x">
<td><xsl:value-of select="concat('0.',.,'.1')" /></td>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
XSLTが難しすぎることについて
XSLT が多すぎて理解できないというあなたのコメントに関連して、XSLT は他の言語と同じであることを覚えておいてください。StackOverflow に 1 つまたは 2 つの質問を投稿するだけでは、言語を理解することは期待できません。長期的には、あなたの利益は投資によって最もよく満たされると思います. XSLT 2 に関する優れた本を手に取って読んでください。適切な本を選べば、驚くほど簡単に学べる言語です。それが私が行ったことであり、私の投資に対する利益は十分であることがわかりました.