Re: [xsl] Re: Avoid repition of data

Subject: Re: [xsl] Re: Avoid repition of data
From: Brandon Ibach <brandon.ibach@xxxxxxxxxxxxxxxxxxx>
Date: Sat, 25 Dec 2010 00:27:36 -0500
I don't know that this really has to do with grouping, but I'm also
not completely clear on what the desired result is, either.  Not
having run it through a processor and not completely trusting my
"wetware" (love that term, Wendell) version, I'm not even sure what
the current result is.  Let me say that I echo all of the comments by
the Michaels.

However, I will comment on the things in your XSLT fragment that jump
out at me.  If that doesn't clear up what you need to do, please
consider posting the actual and desired results for the sample input
and XSLT you gave.

On Fri, Dec 24, 2010 at 4:19 AM, Rashi Bhardwaj
<rashi.bhardwaj@xxxxxxxxx> wrote:
>> And here is xsl logic I have used to print it
>>
>> <xsl:for-each select="descendant::SAItem[count(SALevel)=0]">
>>                                <xsl:sort
select="ancestor-or-self::SAItem/SAProperty/@SAPrpValue[1]"
>> data-type="text"/>

While this sort is probably having what I guess to be the desired
result (sorting the SAItem elements by the "Application" property of
itself or its "parent" SAItem), I suspect it is more by chance than
design, which is worth addressing, since such luck rarely holds out
for long. ;)

Given that this template only matches SAItem elements, the first step
in the path will return the current element and all "parent"
(ancestor, really) SAItems.  The second step will grab the SAProperty
children and the third step will return the first SAPrpValue attribute
of each, since the "first only" predicate applies to just that step,
which is executed separately for each SAProperty element matched in
the previous step, with the result being the union of the result of
all of these executions.

Of course, there can only be one such attribute for each SAProperty
element, so this predicate doesn't really do anything.  I suspect the
intent was to select the first SAPrpValue attribute in document order,
which happens to be accomplished (here's where the chance comes into
play) because the sort instruction takes the string value of the
result of the select expression, as if by the string() function.
Since the expression returns a node set, this will be the string value
of the first node in the set, in document order.

>>                                <tr>
>>                                        <xsl:for-each
>> select="ancestor-or-self::SAItem/SAProperty[@SAPrpName !='Invisible'
>> and @SAPrpName !='##Invisible##']">

This, I suspect, is where you're getting results other than what you
want.  This path starts out very similar to the one in your sort,
ultimately grabbing the properties of both the current item and any
"parent" SAItems.  If you only intended to grab the properties for the
current item and not those of the parent item, you might put a "[1]"
predicate after "SAItem" in the first step.  However, given that you
know this template will only ever match an SAItem, you could also just
omit the first step altogether, since you're already on the SAItem.

If you want to include the parent item properties for just the first
SAItem in a set of siblings, you might try something like this for the
"select" expression on the for-each:

(. | self::SAItem[count(preceding-sibling::SAItem)=0]/ancestor::SAItem)/
    SAProperty[not(@SAPrpName = 'Invisible' or @SAPrpName = '##Invisible##')]

That is, get the properties for the current item and, if the current
item has no preceding siblings, ancestor items.  I adjusted the
predicate a little to a form I usually prefer because it is more
robust in cases where SAPrpName is missing altogether.  Your data
might be designed to always have that attribute present, but it almost
never hurts to be overly cautious about such "guaranteed" things. :)

>>                                                <xsl:choose>
>>                                                        <xsl:when
test="./@SAPrpValue=''">
>>                                                                <td
style="border:solid 1px #dddddd;padding-left:5px;background-color: #FFFF33;">
>>                                                                      
 <!--<xsl:apply-templates select="." mode="FormatOutputString"/-->
>>                                                                      
 <xsl:text>-</xsl:text>
>>                                                                </td>
>>                                                        </xsl:when>
>>                                                        <xsl:otherwise>
>>                                                                <td
style="border:solid 1px #dddddd;padding-left:5px;">
>>                                                                      
 <!--<xsl:apply-templates select="." mode="FormatOutputString"/-->
>>                                                                      
 <xsl:value-of select="./@SAPrpValue"/>
>>                                                                </td>
>>                                                        </xsl:otherwise>
>>                                                </xsl:choose>
>>                                        </xsl:for-each>
>>                                </tr>
>>                        </xsl:for-each>
>> --
>> My problem is for the SAItem with SALevel Number ="3", in this case
>> the SAProperty with SAPrpName="Application" is repeating each time for
>> each row. For example, for SALevel Number="3", Application 'Adobe
>> Acrobat (Pro and Standard)' is appearing four times for each nested
>> SAItem, i.e. 1 Adobe Acrobat (7.0), 2 Adobe Acrobat (7.0).....4 Adobe
>> Acrobat (7.0). I want it should appear only for first nested SAItem
>> and not for rest three nested SAItem.

Standard disclaimers apply about code provided above (typed right into
the email message... not actually tested... YMMV).

Hope this helps.

-Brandon :)

Current Thread