需要从列表中选择四种类型的数据并将其分组到表中。 XML输入的示例如下所示:
<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>fr.0.7.1 : en1.5.1</li>
<li> : en1.6.1</li>
</ul
</DIV>
具有相同前缀(例如'fr')的每个3位数字中的第2个数字相对于前后3位数字的第2个数字,例如, fr0.1.1,fr0.2.1,fr0.3.1在此上下文中是连续序列,而fr0.1.1,fr0.3.1,fr0.2.1或fr0.1.1,fr0.3.1是不连续的。
我需要一个代码,只能在每个&lt; li&gt;左侧的前缀为'fr'的数字中找到这些关系中的间隙和差异。元件。如果在这样的序列中缺少一个数字,则代码需要检索它并将其列在名为“Absent(fr)”的第一列中。如果第二个数字没有按照增长顺序排列,当你在左边的所有3位数字列表中,代码应该识别第二个数字是增长顺序的差异的数字,例如,对于(0。)4(.1)&lt;(0。)6(。1)&gt;(0。)5(.1),在上面的输入示例中为fr0.6.1。如果找到这样的数字,它应该列在名为“Discrepant”的第二列中。第三列应列出差异数字在其右侧匹配的数字。
名为'No-match(en)'的第四列应列出前缀为'en'的数字,前提是它们的右边没有前缀为'fr'的匹配项。在这个例子中,这个数字是1.6.1。
第五列colled'Repetition'应列出前缀为'en'的数字,如果它只在输入列表中出现多次。代码应检索重复数字前缀为'fr'的匹配项,并将其列在最后一列'匹配'中。
HTML输出中的表应该看起来像这样(颜色或粗体等样式并不重要!):
xml输出看起来像这样:
<table>
<tr>
<th>Absent(en)</th>
<th>Discrepant</th>
<th>Match</th>
<th>No-match(en)</th>
<th>Repetition</th>
<th>Matches</th>
</tr>
<tr>
<td>0.3.1</td>
<td>0.6.1</td>
<td>1.4.1</td>
<td>1.6.1</td>
<td>1.5.1</td>
<td>0.5.1, 0.7.1</td>
</tr>
</table>
答案 0 :(得分:0)
我不会回答你的整个问题。对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>
..这是两个缺席的li值。
您可以使用xsl:for-each-group / @ group-adjacent指令,对一个li节点的值与其前一个节点之间的差值进行分组。这为您提供了一组顺序节点。因此,只需跨越一组结束与下一组开始之间的差异,即可得到所有缺席值。这将为您提供第一列。
对其他列使用类似的技术。
我刚刚意识到你不需要so:inbetween()函数。您只需使用to
运算符即可。对于那个很抱歉。更改为to
运算符应大大简化样式表。
这是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就像任何其他语言一样。你不能期望通过在StackOverflow上发布一两个问题来获取语言。我怀疑从长远来看,投资可以最好地满足您的利益。拿起一本关于XSLT 2的好书并阅读它。如果你选择合适的书,它实际上是一种非常容易学习的语言。这就是我所做的,而且我发现投资回报充足。