开发者

Get xsl 1.0 to only show first item in a group within a list

开发者 https://www.devze.com 2023-03-20 02:05 出处:网络
This is for a category index of blog posts-I only want to show the category once using xsl v1.0. There will be multiple posts in each category. The desired result is:

This is for a category index of blog posts-I only want to show the category once using xsl v1.0. There will be multiple posts in each category. The desired result is:

Cat Name 1
cat Name 2
Cat Name 3 

I assume grouping the items and only showing the first one in a group (using the cat name as a key) would work but the Muenchian method is a bit beyond my abilities. So a simpler method or a sim开发者_如何学JAVAple explanation of the Muenchian method would be most appreciated.

The xml

<Root>
<Schema>
<Field Type="Lookup" DisplayName="Category name" Required="FALSE" ShowField="Category_x0020_name" Name="Category_x0020_name"  Group="" />
<Field ReadOnly="TRUE" Type="Computed" Name="LinkTitle" DisplayName="Post number" />
</Schema>
<Data ItemCount="1">
<Row  Category_x0020_name=""  LinkTitle="" /> 
</Data>
</Root>

The xsl:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />      
  <xsl:template match="/">
   <table border="0" cellpadding="0" cellspacing="0">     
 <h3>Categories</h3>
 <xsl:for-each select="//Data/Row">
                <xsl:if test="./@Category_x0020_name !=''"> 
 <tr valign="top">         <td>               
 <a href="/cat{./@LinkTitle}.aspx">  
 <xsl:value-of select="./@Category_x0020_name" /></a></td> </tr>
 </xsl:if>
 </xsl:for-each>
 </table>
 </xsl:template> 
 </xsl:stylesheet> 


Do not be afraid of Meunchian method. Use it once, and you will be able to apply it whenever you need it.

  • collect the wanted data to group in a key
  • apply the templates to only one node with same key using a predicate like

generate-id()=generate-id(key(...)[1])

That's what you need know to use Meunchian grouping. Here to get you started:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="Cat" match="Data/Row" use="@Category_x0020_name"/>

    <xsl:template match="/*/Data">
        <xsl:apply-templates select="Row
            [generate-id()
            = generate-id(key('Cat',@Category_x0020_name)[1])]"/>
    </xsl:template>

    <xsl:template match="Row">
        <xsl:value-of select="concat(@Category_x0020_name,'&#xA;')"/>
    </xsl:template>

</xsl:stylesheet>


Since you don't need to list the members of each category, and assuming your data sets are not very large so performance is not a big factor, you can forego Muenchian grouping for something a little less elegant. Just change your <xsl:if test> to:

        <xsl:if test="./@Category_x0020_name !='' and
             not(./@Category_x0020_name = preceding::Row/@Category_x0020_name)">

In other words, only output a category name the first time it occurs.

Incidentally, you can remove the ./ wherever it occurs at the beginning of an XPath expression. It's redundant. It means "starting from the context node," but you're already starting from the context node. If you want to leave it in for readability or something, that's OK.

Then with input like

<Root>...
   <Data ItemCount="1">
      <Row  Category_x0020_name="foo"  LinkTitle="Foo" /> 
      <Row  Category_x0020_name="bar"  LinkTitle="Bar" /> 
      <Row  Category_x0020_name="foo"  LinkTitle="Foo" /> 
   </Data>
</Root>

You get this output:

<table border="0" cellpadding="0" cellspacing="0">
   <h3>Categories</h3>
   <tr valign="top">
      <td><a href="/catFoo.aspx">foo</a></td>
   </tr>
   <tr valign="top">
      <td><a href="/catBar.aspx">bar</a></td>
   </tr>
</table>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号