给出以下XML:
<databases>
<database>
<title_display>Aardvark</title_display>
</database>
<database>
<title_display>Apple</title_display>
</database>
<database>
<title_display>Blue</title_display>
</database>
<database>
<title_display>Car</title_display>
</database>
</databases>
如何使用XSLT获取以下HTML输出?
<h2>A</h2>
<div class="a-content">
<ul>
<li>Aardvark</li>
<li>Aardvark</li>
</ul>
</div>
<h2>B</h2>
<div class="b-content">
<ul>
<li>Blue</li>
</ul>
</div>
<h2>C</h2>
<div class="c-content">
<ul>
<li>Car</li>
</ul>
</div>
我可以放心地假设所有<database>
元素都已按字母顺序排列。谢谢!
编辑:为了将来参考,“Accordion”部分是HTML被转换为带有JavaScript的accordion元素。
答案 0 :(得分:3)
这是一个更有效的解决方案,使用经典的Muenchian方法进行分组 - 使用键。
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLower" select=
"'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select=
"'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:key name="kTitleBy1stLetter" match="database"
use="substring(title_display,1,1)"/>
<xsl:template match="/*">
<xsl:for-each select=
"database
[generate-id()
=
generate-id(key('kTitleBy1stLetter',
substring(title_display,1,1)
)[1]
)
]"
>
<xsl:variable name="v1st"
select="substring(title_display,1,1)"/>
<h2><xsl:value-of select="$v1st"/></h2>
<div class="{translate($v1st,
$vUpper,
$vLower)}-content">
<ul>
<xsl:for-each select=
"key('kTitleBy1stLetter',$v1st)">
<li><xsl:value-of select="title_display"/></li>
</xsl:for-each>
</ul>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
应用于最初提供的XML文档:
<databases>
<database>
<title_display>Aardvark</title_display>
</database>
<database>
<title_display>Apple</title_display>
</database>
<database>
<title_display>Blue</title_display>
</database>
<database>
<title_display>Car</title_display>
</database>
</databases>
产生完全想要的结果:
<h2>A</h2>
<div class="a-content">
<ul>
<li>Aardvark</li>
<li>Apple</li>
</ul>
</div>
<h2>B</h2>
<div class="b-content">
<ul>
<li>Blue</li>
</ul>
</div>
<h2>C</h2>
<div class="c-content">
<ul>
<li>Car</li>
</ul>
</div>
请注意,Muenchian方法比使用database
上所有preceding-sibling::
元素的比较的O(N ^ 2)解决方案更有效率
轴。
此外,此解决方案还会生成具有所需大小写的class
属性值。
答案 1 :(得分:1)
您可以尝试将其用于分组。请注意,xslt2.0有一个for-each-groups,这使得这更容易。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="/databases">
<xsl:for-each select="database">
<xsl:variable name="Init" select="substring(title_display,1,1)"/>
<xsl:if test="not(preceding-sibling::*[substring(title_display,1,1)=$Init])">
<h2><xsl:value-of select="$Init"/></h2>
<div>
<xsl:attribute name="class">
<xsl:value-of select="$Init"/><xsl:text>-content</xsl:text>
</xsl:attribute>
<ul>
<xsl:for-each select="../database[substring(title_display,1,1)=$Init]">
<li><xsl:value-of select="title_display"/></li>
</xsl:for-each>
</ul>
</div>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
这可以循环遍历所有数据库,但只发送以每个字母开头的第一个数据库的数据。然后,它会选择以该字母开头的所有项目,并将它们作为一个组进行处理。
您的另一个选择是使用xslt中的Muenchian method分组。
答案 2 :(得分:0)
以下是Josh解决方案的不区分大小写的版本:
<xsl:variable name="lower">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="upper">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:for-each select="databases/database">
<xsl:variable name="Init" select="translate(substring(title_display,1,1), $lower, $upper)"/>
<xsl:if test="not(preceding-sibling::*[translate(substring(title_display,1,1), $lower, $upper)=$Init])">
<h2><xsl:value-of select="$Init"/></h2>
<div>
<xsl:attribute name="class">
<xsl:value-of select="translate(substring($Init,1,1), $upper, $lower)"/><xsl:text>-content</xsl:text>
</xsl:attribute>
<ul>
<xsl:for-each select="../database[translate(substring(title_display,1,1), $lower, $upper)=$Init]">
<li><xsl:value-of select="title_display"/></li>
</xsl:for-each>
</ul>
</div>
</xsl:if>
</xsl:for-each>