下面的XSLT转换如何更简洁?它工作正常,但我仍然无法以声明方式看到问题(作为一个相对的XSLT新手),并且觉得这个解决方案是一个程序性的&相当冗长的解决方案。我想看看对声明性方法有直觉感觉的人如何解决/简化它?
XSLT用于构造具有三个深度级别的垂直导航元素。导航元素根据选择的节点进行扩展/折叠。根据选择的级别,也会应用Css类(活动)。
它需要2个参数,id和query_string。
在XML中有一个特殊情况节点'新闻' - 来自此节点的所有后代节点具有相同的id,因此query_string用于区分它们。
这是XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" omit-xml-declaration="yes" indent="yes" />
<xsl:param name="id" select="'id:144016'"></xsl:param>
<xsl:param name="query_string" select="'year=2012&month=12'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="//siteMapNode[@id=$id and @query_string=$query_string]">
<xsl:apply-templates select="//siteMapNode[@id=$id and @query_string=$query_string]/ancestor-or-self::*[@depth=1]" />
</xsl:when>
<xsl:when test="//siteMapNode[@id=$id]/ancestor::*[@depth=1]">
<xsl:apply-templates select="//siteMapNode[@id=$id]/ancestor-or-self::*[@depth=1]" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="//siteMapNode[@id=$id]" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="siteMapNode/siteMapNode/siteMapNode">
<xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=substring($query_string, 1, 9)])" />
<xsl:variable name="matchid" select="count(self::node()[@id=$id])" />
<xsl:variable name="matchdescendentid" select="count(self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)])" />
<li>
<xsl:if test="$matchidandyearpartofquery > 0 or $matchdescendentid > 0">
<xsl:attribute name="class">
<xsl:text>active</xsl:text>
</xsl:attribute>
</xsl:if>
<a>
<xsl:attribute name="href">
<xsl:value-of select="@url" />
</xsl:attribute>
<xsl:value-of select="@title" />
</a>
<xsl:choose>
<xsl:when test="self::node()[@id=$id and @query_string=substring($query_string, 1, 9)]">
<xsl:if test="./*">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:when>
<xsl:when test="self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)]">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:when>
<xsl:when test="self::node()[@id=$id]">
<xsl:if test="./*">
<xsl:if test="./*[not(@id=$id)]">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:if>
</xsl:when>
<xsl:when test="self::node()//*[@id=$id]">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:template>
<xsl:template match="siteMapNode/siteMapNode/siteMapNode/siteMapNode">
<xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=$query_string])" />
<xsl:variable name="matchid" select="count(self::node()[@id=$id])" />
<xsl:variable name="matchdescendentid" select="count(self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)])" />
<li>
<xsl:if test="$matchidandyearpartofquery > 0 or $matchdescendentid > 0">
<xsl:attribute name="class">
<xsl:text>active icon-nav-left</xsl:text>
</xsl:attribute>
</xsl:if>
<a>
<xsl:attribute name="href">
<xsl:value-of select="@url" />
</xsl:attribute>
<xsl:value-of select="@title" />
</a>
<xsl:choose>
<xsl:when test="self::node()[@id=$id and @query_string=$query_string]">
<xsl:if test="./*">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:when>
<xsl:when test="self::node()//*[@id=$id and @query_string=substring($query_string, 1, 9)]">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:when>
<xsl:when test="self::node()[@id=$id]">
<xsl:if test="./*">
<xsl:if test="./*[not(@id=$id)]">
<ul>
<xsl:apply-templates select="siteMapNode">
<xsl:sort select="@month" data-type="number" order="descending"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:if>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</li>
</xsl:template>
<xsl:template match="siteMapNode/siteMapNode/siteMapNode/siteMapNode/siteMapNode">
<xsl:variable name="matchidandyearpartofquery" select="count(self::node()[@id=$id and @query_string=$query_string])" />
<li>
<xsl:if test="$matchidandyearpartofquery > 0">
<xsl:attribute name="class">
<xsl:text>active icon-nav-left</xsl:text>
</xsl:attribute>
</xsl:if>
<a>
<xsl:attribute name="href">
<xsl:value-of select="@url" />
</xsl:attribute>
<xsl:value-of select="@title" />
</a>
</li>
</xsl:template>
</xsl:stylesheet>
一些XML输入示例
<siteMapNode id="id:144037" title="Home" url="index.jsp" depth="0" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year="">
<siteMapNode id="id:144037" title="Home" url="index.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144513" title="Company" url="our-company/index.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year="">
<siteMapNode id="id:144615" title="At a glance" url="our-company/at-a-glance.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144005" title="Our Brands" url="our-company/our-brands.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144629" title="Our Products" url="our-company/our-products.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144638" title="Our Global Purpose" url="our-company/our-global-purpose.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144002" title="Company History" url="our-company/company-history.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
<siteMapNode id="id:144003" title="Leadership" url="our-company/leadership.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="" month="" year="" />
</siteMapNode>
<siteMapNode id="id:144016" title="News" url="news-press/newslisting.jsp" depth="1" show_in_top="Yes" show_in_footer="No" use_as_default="No" query_string="" month="" year="">
<siteMapNode id="id:144016" title="2012 Archive" url="news-press/newslisting.jsp?year=2012" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012" month="" year="2012">
<siteMapNode id="id:144016" title="December" url="news-press/newslisting.jsp?year=2012&month=12" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&month=12" month="12" year="2012" />
<siteMapNode id="id:144016" title="April" url="news-press/newslisting.jsp?year=2012&month=4" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&month=4" month="4" year="2012" />
</siteMapNode>
<siteMapNode id="id:144016" title="2013 Archive" url="news-press/newslisting.jsp" depth="2" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2013" month="" year=""/>
</siteMapNode>
</siteMapNode>
以下是预期输出HTML的示例(此处,2012年12月从新闻栏目中选出)
<li class="active"><a href="news-press/newslisting.jsp?year=2012">2012 Archive</a>
<ul>
<li class="active icon-nav-left"><a href="news-press/newslisting.jsp?year=2012&month=12">December</a></li>
<li><a href="news-press/newslisting.jsp?year=2012&month=4">April</a></li>
</ul>
</li>
<li><a href="news-press/newslisting.jsp">2013 Archive</a></li>
答案 0 :(得分:1)
这是我的解决方案,希望有用的评论。它适用于您的示例,但您可能有更多不需要考虑的具体要求。不过,我希望它对你有用。
以下XSLT样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="id" select="'id:144016'"></xsl:param>
<xsl:param name="query_string" select="'year=2012&month=12'"/>
<!-- Match the siteMapNode element at depth 1 with the specified id. Just apply
templates to its children. -->
<xsl:template match="siteMapNode[@id=$id and @depth='1']"
priority="5">
<xsl:apply-templates select="node()|@*"/>
</xsl:template>
<!-- Match the siteMapNode element with the specified id that partially match the
query string. These will have child elements so apply templates and keep
going. -->
<xsl:template match="siteMapNode[@id=$id and contains($query_string, @query_string)]"
priority="1">
<li class="active">
<xsl:call-template name="anchor"/>
<ul>
<xsl:apply-templates select="node()|@*"/>
</ul>
</li>
</xsl:template>
<!-- Match the siteMapNode element with the specified id that completely match the
query string. -->
<xsl:template match="siteMapNode[@id=$id and $query_string=@query_string]"
priority="10">
<li class="active icon-nav-left">
<xsl:call-template name="anchor"/>
</li>
</xsl:template>
<!-- Match the remaining siteMapNode elements with the specified id.
This template has the default priority of 0.5. -->
<xsl:template match="siteMapNode[@id=$id]">
<li>
<xsl:call-template name="anchor"/>
</li>
</xsl:template>
<!-- The anchor element we output is common, so put it into a template we can call. -->
<xsl:template name="anchor">
<a href="{@url}">
<xsl:value-of select="@title"/>
</a>
</xsl:template>
<!-- The built-in template for elements and the root node is already doing what we want,
so we don't need to include it explicitly. It's below, commented out, for
reference. -->
<!-- <xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>-->
<!-- Don't want to output text or attribute nodes unless we explicitly say so, so we
need to override the built-in templates for these. -->
<xsl:template match="text()|@*"/>
</xsl:stylesheet>
在应用于示例输入XML时提供以下输出:
<li class="active"><a href="news-press/newslisting.jsp?year=2012">2012 Archive</a><ul>
<li class="active icon-nav-left"><a href="news-press/newslisting.jsp?year=2012&month=12">December</a></li>
<li><a href="news-press/newslisting.jsp?year=2012&month=4">April</a></li>
</ul>
</li>
<li><a href="news-press/newslisting.jsp">2013 Archive</a></li>