我有以下xsl按字母顺序对我的xml进行排序:
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:key name="rows-by-title" match="Row" use="translate(substring(@Title,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<xsl:variable name="StartRow" select="string('<tr >')" />
<xsl:template name="Meunchian" match="/dsQueryResponse/Rows">
<table>
<tr>
<xsl:for-each select="Row[count(. | key('rows-by-title', translate(substring(@Title,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'))[1]) = 1]">
<xsl:sort select="translate(substring(@Title,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<!-- Puts out the title -->
<td>
<xsl:value-of select="translate(substring(@Title,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
</td>
<!-- Now all it's children -->
<xsl:for-each select="key('rows-by-title', translate(substring(@Title,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'))">
<xsl:value-of select="@Title" /><br/>
</xsl:for-each>
</xsl:for-each>
</tr>
</table>
</xsl:template>
XML:
<dsQueryResponse>
<Rows>
<Row Title="Agenda" />
<Row Title="Policy" />
<Row Title="Policy" />
<Row Title="Report" />
<Row Title="Report" />
</Rows>
</dsQueryResponse>
我现在想要每4个输出的列中断表行,以便输出看起来像:
ABCD
EFGH
IJKL
MNOP
QRST
UVWX
YZ
有人能提出实现这个目标的最佳方法吗?
非常感谢
答案 0 :(得分:3)
这是我的解决方案。
如果要显示空单元格或者是否要隐藏它们,可以通过参数"per-row"
和"show-empty"
来决定。我确信存在一个更优雅的版本,但我无法想出一个版本。 ;-)评论欢迎。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="4.0" encoding="iso-8859-1" indent="yes"/>
<xsl:key name="rows-by-title" match="Row" use="translate(substring(@Title, 1, 1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<xsl:variable name="alphabet" select="string('ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<xsl:variable name="per-row" select="number(4)" />
<xsl:variable name="show-empty" select="false()" />
<xsl:template match="/">
<xsl:apply-templates select="dsQueryResponse/Rows" />
</xsl:template>
<xsl:template match="Rows">
<table>
<xsl:call-template name="create-rows" />
</table>
</xsl:template>
<xsl:template name="create-rows">
<xsl:param name="index" select="1" />
<xsl:variable name="letters">
<xsl:call-template name="next-letters">
<xsl:with-param name="index" select="$index" />
</xsl:call-template>
</xsl:variable>
<xsl:if test="$letters != ''">
<tr title="{$letters}">
<xsl:call-template name="create-cells">
<xsl:with-param name="letters" select="$letters" />
</xsl:call-template>
</tr>
</xsl:if>
<xsl:if test="string-length($letters) = $per-row">
<xsl:call-template name="create-rows">
<xsl:with-param name="index" select="string-length(substring-before($alphabet, substring($letters, string-length($letters), 1))) + 2" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="next-letters">
<xsl:param name="index" />
<xsl:variable name="letter" select="substring($alphabet, $index, 1)" />
<xsl:variable name="letters">
<xsl:if test="$index <= string-length($alphabet)">
<xsl:if test="$show-empty or key('rows-by-title', $letter)">
<xsl:value-of select="$letter" />
</xsl:if>
<xsl:call-template name="next-letters">
<xsl:with-param name="index" select="$index + 1" />
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:value-of select="substring($letters, 1, $per-row)" />
</xsl:template>
<xsl:template name="create-cells">
<xsl:param name="letters" />
<xsl:variable name="letter" select="substring($letters, 1, 1)" />
<xsl:if test="$letter != ''">
<td title="{$letter}">
<strong>
<xsl:value-of select="$letter" />
</strong>
<xsl:apply-templates select="key('rows-by-title', $letter)">
<xsl:sort select="@Title" />
</xsl:apply-templates>
</td>
<xsl:call-template name="create-cells">
<xsl:with-param name="letters" select="substring($letters, 2, string-length($letters) - 1)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Row">
<br />
<xsl:value-of select="@Title" />
</xsl:template>
</xsl:stylesheet>
使用此输入:
<dsQueryResponse>
<Rows>
<Row Title="Agenda" />
<Row Title="Policy" />
<Row Title="Policy" />
<Row Title="Report" />
<Row Title="Report" />
<Row Title="Test2" />
<Row Title="Test1" />
<Row Title="Boo" />
<Row Title="Foo" />
</Rows>
</dsQueryResponse>
生成此输出(title
属性仅用于调试。我将它们保留,随时删除它们):
<table>
<tr title="ABFP">
<td title="A">
<strong>A</strong>
<br>Agenda
</td>
<td title="B">
<strong>B</strong>
<br>Boo
</td>
<td title="F">
<strong>F</strong>
<br>Foo
</td>
<td title="P">
<strong>P</strong>
<br>Policy
<br>Policy
</td>
</tr>
<tr title="RT">
<td title="R">
<strong>R</strong>
<br>Report
<br>Report
</td>
<td title="T">
<strong>T</strong>
<br>Test1
<br>Test2
</td>
</tr>
</table>
答案 1 :(得分:1)
必须编辑此问题才能让任何人了解问题的真正含义。 Tomalak的评论显示OP“想要按字母顺序排列的网格中的项目列表。每个字母一个列表。水平四个字母,垂直方向”
以下转型:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
extension-element-prefixes="ext"
>
<xsl:variable name="vDoc" select="/"/>
<xsl:variable name="vNumCols" select="4"/>
<xsl:variable name="vLower"
select="'abcdefghijklmnopqrstuvwxyz'"
/>
<xsl:variable name="vUpper"
select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"
/>
<xsl:key name="rows-by-FirstLetter" match="Row"
use="translate(substring(@Title,1,1),
'abcdefghijklmnopqrstuvwxyz',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<xsl:variable name="vrtfStartLetters">
<xsl:for-each select=
"/*/*/Row
[count(.
|
key('rows-by-FirstLetter',
translate(substring(@Title,1,1),
$vLower,
$vUpper)
)[1]
)
= 1
]">
<startLetter>
<xsl:value-of select=
"translate(substring(@Title,1,1),
$vLower,
$vUpper)"/>
</startLetter>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="vStartLetters" select=
"ext:node-set($vrtfStartLetters)"/>
<xsl:template match="Rows">
<table>
<xsl:apply-templates select=
"$vStartLetters/*[position() mod $vNumCols = 1]">
<xsl:with-param name="pDoc" select="$vDoc"/>
<xsl:with-param name="pNumCols" select="$vNumCols"/>
</xsl:apply-templates>
</table>
</xsl:template>
<xsl:template match="startLetter">
<xsl:param name="pDoc"/>
<xsl:param name="pNumCols" select="10"/>
<tr>
<xsl:apply-templates mode="copy" select=
". | following-sibling::*
[not(position() >= $pNumCols)]">
<xsl:with-param name="pDoc" select="$pDoc"/>
<xsl:sort/>
</xsl:apply-templates>
</tr>
</xsl:template>
<xsl:template match="startLetter" mode="copy">
<xsl:param name="pDoc"/>
<xsl:variable name="pThis" select="."/>
<td>
<xsl:value-of select="."/>
<br />
<table>
<xsl:for-each select="$pDoc">
<xsl:for-each select="key('rows-by-FirstLetter', $pThis)">
<tr><td><xsl:value-of select="@Title"/></td></tr>
</xsl:for-each>
</xsl:for-each>
</table>
</td>
</xsl:template>
</xsl:stylesheet>
应用于此XML文档时:
<dsQueryResponse>
<Rows>
<Row Title="Agenda" />
<Row Title="Accrual" />
<Row Title="Ads" />
<Row Title="Averages" />
<Row Title="Bindings" />
<Row Title="Budget" />
<Row Title="Cars" />
<Row Title="Categories" />
<Row Title="Costs" />
<Row Title="Policy" />
<Row Title="Politics" />
<Row Title="Reevaluations" />
<Row Title="Report" />
</Rows>
</dsQueryResponse>
产生想要的结果:
<table>
<tr>
<td>A
<br/>
<table>
<tr>
<td>Agenda</td>
</tr>
<tr>
<td>Accrual</td>
</tr>
<tr>
<td>Ads</td>
</tr>
<tr>
<td>Averages</td>
</tr>
</table>
</td>
<td>B
<br/>
<table>
<tr>
<td>Bindings</td>
</tr>
<tr>
<td>Budget</td>
</tr>
</table>
</td>
<td>C
<br/>
<table>
<tr>
<td>Cars</td>
</tr>
<tr>
<td>Categories</td>
</tr>
<tr>
<td>Costs</td>
</tr>
</table>
</td>
<td>P
<br/>
<table>
<tr>
<td>Policy</td>
</tr>
<tr>
<td>Politics</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>R
<br/>
<table>
<tr>
<td>Reevaluations</td>
</tr>
<tr>
<td>Report</td>
</tr>
</table>
</td>
</tr>
</table>
请注意三件事:
我们使用(exslt)ext:node-set()扩展函数将RTF(结果树片段)的中间结果转换为临时树。
使原始XML文档再次成为当前XML文档所需的<xsl:for-each select="$pDoc">
,以便key()函数将使用为此文档而不是临时树创建的索引。
每个必须开始新行(4)首字母的起始字母都在特殊模板中处理,其中生成<tr>
。然后,此行和行中剩余的(3)个起始字母将在{copy}模式的<tr>
正文中处理,只需创建一个<td>
。
这里我们介绍并演示了一些高级XSLT技术:
享受:)
答案 2 :(得分:0)
这是第二种解决方案,不需要任何扩展功能。请注意它不是递归的,并且可能比递归效率更高。
此转化:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:namespace" exclude-result-prefixes="my" > <xsl:output method="html"/> <my:alpha> <l>A</l><l>B</l><l>C</l><l>D</l><l>E</l> <l>F</l><l>G</l><l>H</l><l>I</l><l>J</l> <l>K</l><l>L</l><l>M</l><l>N</l><l>O</l> <l>P</l><l>Q</l><l>R</l><l>S</l><l>T</l> <l>U</l><l>V</l><l>W</l><l>X</l><l>Y</l> <l>Z</l> </my:alpha> <xsl:variable name="vDoc" select="/"/> <xsl:variable name="vNumCols" select="4"/> <xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'" /> <xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" /> <xsl:key name="rows-by-FirstLetter" match="Row" use="translate(substring(@Title,1,1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" /> <xsl:variable name="vStartingLetters"> <xsl:for-each select= "/*/*/Row [generate-id() = generate-id(key('rows-by-FirstLetter', translate(substring(@Title,1,1), $vLower, $vUpper) )[1] ) ]"> <xsl:value-of select= "translate(substring(@Title,1,1), $vLower, $vUpper)"/> </xsl:for-each> </xsl:variable> <xsl:variable name="vMyLetters" select= "document('')/*/my:alpha/l[contains($vStartingLetters,.)]" /> <xsl:template match="Rows"> <table> <xsl:for-each select= "$vMyLetters[position() mod $vNumCols = 1]"> <xsl:variable name="vPos" select="(position()-1)*$vNumCols+1"/> <tr> <xsl:apply-templates select= "$vMyLetters[position() >= $vPos and not(position() > $vPos+$vNumCols -1) ]"> <xsl:with-param name="pDoc" select="$vDoc"/> </xsl:apply-templates> </tr> </xsl:for-each> </table> </xsl:template> <xsl:template match="l"> <xsl:param name="pDoc"/> <xsl:variable name="pThis" select="."/> <td> <xsl:value-of select="."/> <br /> <table> <xsl:for-each select="$pDoc"> <xsl:for-each select= "key('rows-by-FirstLetter', $pThis)"> <tr> <td> <xsl:value-of select="@Title"/> </td> </tr> </xsl:for-each> </xsl:for-each> </table> </td> </xsl:template> </xsl:stylesheet>
应用于以下XML文档时:
<dsQueryResponse> <Rows> <Row Title="Agenda" /> <Row Title="Policy" /> <Row Title="Policy" /> <Row Title="Report" /> <Row Title="Report" /> <Row Title="Test2" /> <Row Title="Test1" /> <Row Title="Boo" /> <Row Title="Foo" /> </Rows> </dsQueryResponse>
产生想要的结果:
<table> <tr> <td>A<br><table> <tr> <td>Agenda</td> </tr> </table> </td> <td>B<br><table> <tr> <td>Boo</td> </tr> </table> </td> <td>F<br><table> <tr> <td>Foo</td> </tr> </table> </td> <td>P<br><table> <tr> <td>Policy</td> </tr> <tr> <td>Policy</td> </tr> </table> </td> </tr> <tr> <td>R<br><table> <tr> <td>Report</td> </tr> <tr> <td>Report</td> </tr> </table> </td> <td>T<br><table> <tr> <td>Test2</td> </tr> <tr> <td>Test1</td> </tr> </table> </td> </tr> </table>
请注意我的第一个回答中的大多数解释也适用于此解决方案,唯一的例外是我们不使用模式。
答案 3 :(得分:-1)
我对这个问题感到困惑,但我认为你要找的是一个xsl:if test with position()和mod