2013-09-24 5 views
0

Как преобразование XSLT ниже будет более кратким? Он работает, но я все еще не смог увидеть проблему декларативно (будучи относительным новичком XSLT), и считаю, что это решение является процедурным & довольно подробным решением. Я хотел бы видеть, как кто-то с интуитивным чувством к декларативному подходу решит/упростит его?Более краткий/эффективный XSLT

XSLT используется для построения вертикального навигационного элемента с тремя уровнями глубины. Элемент навигации расширяется/сворачивается в зависимости от выбранного узла. Классы Css (активные) также применяются в зависимости от выбранного уровня.

Требуется 2 параметра, id и query_string.

В XML это особый случайный узел «Новости» - все узлы-потомки этого узла имеют одинаковый идентификатор, поэтому для различения между ними используется 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&amp;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 &gt; 0 or $matchdescendentid &gt; 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 &gt; 0 or $matchdescendentid &gt; 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 &gt; 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&amp;month=12" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&amp;month=12" month="12" year="2012" /> 
     <siteMapNode id="id:144016" title="April" url="news-press/newslisting.jsp?year=2012&amp;month=4" depth="3" show_in_top="No" show_in_footer="No" use_as_default="No" query_string="year=2012&amp;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 году из секции новостей)

<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&amp;month=12">December</a></li> 
    <li><a href="news-press/newslisting.jsp?year=2012&amp;month=4">April</a></li> 
    </ul> 
</li> 
<li><a href="news-press/newslisting.jsp">2013 Archive</a></li> 
+1

Если вы могли бы привести пример вашего входного XML, что помогло бы. –

+1

... и ожидаемый результат. –

+0

Я добавил примеры обоих - лучше? – jag

ответ

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&amp;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 [email protected]_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&amp;month=12">December</a></li> 
     <li><a href="news-press/newslisting.jsp?year=2012&amp;month=4">April</a></li> 
    </ul> 
</li> 
<li><a href="news-press/newslisting.jsp">2013 Archive</a></li> 
+0

Преобразование не работает для меня, когда я пытаюсь это сделать - говорит, что «переменные не могут использоваться в выражении» ... Я не могу использовать переменные в шаблоне? – jag

+0

Извините, вы правы (хотя это сработало для меня, используя Saxon HE 9.0.4.4N - мне придется больше узнать, почему). Я скоро посмотрю на него и (надеюсь) заработает. –

Смежные вопросы