This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: A better way to build a comma-delimited list
While reading Tom's answer I hope the last lights are switched on in my
head. It takes very long today ...
> <xsl:text>select </xsl:text>
> <xsl:variable name="string">
> <xsl:for-each select="document($pbsdef)/pbsdef/column
> [not(@dbcolumn=preceding-sibling::column/@dbcolumn)]">
> <xsl:variable name="p" select="position()"/>
> <xsl:variable name="dbcolumn" select="@dbcolumn"/>
> <xsl:for-each select="$dbdef[key('dbdef-cols', $dbcolumn)]">
> <xsl:text>, </xsl:text>
> <xsl:value-of select="$dbcolumn"/>
> </xsl:for-each>
> </xsl:for-each>
> </xsl:variable>
> <xsl:value-of select="substring($string, 2)"/>
It's only a bit easier than Tom's solution, because you don't need the
string-length.
Joerg
Joerg Heinicke wrote:
> Oh sorry. Your mail switched some lights on ;-)
>
> I remember that for-each $dbdef was only for switching into the other
> document, wasn't it? Then your solution using $p and $l was absolutely
> correct (in theory). But the problem will still be there. The problem is
> that the nodeset from the outer for-each (which the last() refers too)
> is not the output, because of a further condition (the inner for-each).
> It's really tricky then. If not anybody else has a better solution a
> recursive approach or at least a step-by-step approach (using
> following-sibling::*[1]) can be necessary. The following is not using
> last(), but testing for the first element. It has the same weak point as
> the other one, but maybe works with your code (the first @dbcolumn must
> be in $dbdef). Another possibility
> is using a variable, which stores the string and a recursive template
> which removes all leading commas. Hmm, when writing this a got a new
> idea. When you don't add a comma, but a space before or after a column,
> you can do a normalize-space on the variable and replace every space
> with a comma after this:
>
> <xsl:text>select </xsl:text>
> <xsl:variable name="string">
> <xsl:for-each
> select="document($pbsdef)/pbsdef/column[not(@dbcolumn=preceding-sibling::column/@dbcolumn)]">
>
> <xsl:variable name="p" select="position()"/>
> <xsl:variable name="dbcolumn" select="@dbcolumn"/>
> <xsl:for-each select="$dbdef[key('dbdef-cols', $dbcolumn)]">
> <xsl:if test="$p != 1">
> <xsl:text> </xsl:text>
> </xsl:if>
> <xsl:value-of select="$dbcolumn"/>
> </xsl:for-each>
> </xsl:for-each>
> </xsl:variable>
> <xsl:value-of select="translate(normalize-space($string), ' ', '')"/>
>
> This should result in "select col1,col2,col3".
>
> Regards,
>
> Joerg
>
> John Sands wrote:
>
>> Hi Joerg,
>>
>>
>>> <xsl:for-each select="$dbdef[key('dbdef-cols', $dbcolumn)]">
>>> <xsl:value-of select="$dbcolumn"/>
>>> <xsl:if test="position() != last()">
>>> <xsl:text>, </xsl:text>
>>> </xsl:if>
>>> </xsl:for-each>
>>
>>
>>
>> I loved the solution because it would fix the problem AND make the
>> code shorter. Unfortunately it doesn't work because position() and
>> last() are both 1 so I get:
>>
>> select col1col2col3
>>
>> John
>>
>>
>>
>>
>>
>>> -----Original Message-----
>>> From: Joerg Heinicke <joerg.heinicke@gmx.de>
>>> Sent: Wednesday, May 15, 2002, 3:15:02 AM,
>>> Subject: [xsl] A better way to build a comma-delimited list
>>
>>
>>
>>> Hello John,
>>
>>
>>
>>> > <xsl:for-each select="$dbdef">
>>> > <xsl:if test="key('dbdef-cols', $dbcolumn)">
>>> > <xsl:value-of select="$dbcolumn"/>
>>> > <xsl:if test="$p < $l">
>>> > <xsl:text>, </xsl:text>
>>> > </xsl:if>
>>> > </xsl:if>
>>> > </xsl:for-each>
>>
>>
>>
>>> instead of the for-each + if you can write one for-each with predicate:
>>
>>
>>
>>> <xsl:for-each select="$dbdef[key('dbdef-cols', $dbcolumn)]">
>>
>>
>>
>>> Now the correct nodeset is selected and position() and last() will
>>> work. But they must refer to the inner for-each, so you can't use $p
>>> and $l, but <xsl:if test="position() != last()">.
>>
>>
>>
>>> So, you have then
>>
>>
>>
>>> <xsl:for-each select="$dbdef[key('dbdef-cols', $dbcolumn)]">
>>> <xsl:value-of select="$dbcolumn"/>
>>> <xsl:if test="position() != last()">
>>> <xsl:text>, </xsl:text>
>>> </xsl:if>
>>> </xsl:for-each>
>>
>>
>>
>>> Regards,
>>
>>
>>
>>> Joerg
>>
>>
>>
>>> John Sands schrieb:
>>>
>>>> I have some XSLT that builds a SQL select statement from several input
>>>> documents. Here's a fragment that builds the column list by getting
>>>> each distinct column name from a separate file ($pbsdef) and checking
>>>> that is is defined in another file (referenced by variable $dbdef).
>>>>
>>>> <xsl:text>select </xsl:text>
>>>> <xsl:for-each
>>>> select="document($pbsdef)/pbsdef/column[not(@dbcolumn=preceding-sibling::column/@dbcolumn)]">
>>>>
>>>> <xsl:variable name="p" select="position()"/>
>>>> <xsl:variable name="l" select="last()"/>
>>>> <xsl:variable name="dbcolumn" select="@dbcolumn"/>
>>>> <xsl:for-each select="$dbdef">
>>>> <xsl:if test="key('dbdef-cols', $dbcolumn)">
>>>> <xsl:value-of select="$dbcolumn"/>
>>>> <xsl:if test="$p < $l">
>>>> <xsl:text>, </xsl:text>
>>>> </xsl:if>
>>>> </xsl:if>
>>>> </xsl:for-each>
>>>> </xsl:for-each>
>>>>
>>>> The output of this fragment might be:
>>>>
>>>> select col1, col2, col3
>>>>
>>>> This all works fine, except for one case - where the last column is
>>>> not found in the $dbdef file (where the 'if test=key' fails). Then I
>>>> get:
>>>>
>>>> select col1, col2,
>>>>
>>>> The position() < last() test doesn't work here. Can someone see a
>>>> better way to avoid that last comma?
>>>>
>>>> Thanks,
>>>> John Sands
>>>
>
--
System Development
VIRBUS AG
Fon +49(0)341-979-7419
Fax +49(0)341-979-7409
joerg.heinicke@virbus.de
www.virbus.de
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list