[xsl] Testing if an attribute name is in a list of names

Subject: [xsl] Testing if an attribute name is in a list of names
From: "Paul A. Hoadley" <paulh@xxxxxxxxxxxxxx>
Date: Thu, 19 May 2005 15:25:02 +0930
Hello,

I am writing some XSL to format some MS SQL Server output to HTML.
For the benefit of those who have never seen it, MS SQL Server returns
results as 'row' elements, whose attribute names are the column names,
and whose attribute values are the corresponding column values.  For
example:

  <row Computer="Rohan's PC" Location="IT Dept" Duration="555" /> 
  <row Computer="Pharmacy" Location="Pharmacy" Duration="457" /> 

I am not doing a lot more than formatting this as a HTML table, so
initially I had a template matching 'row' which simply pulled out the
attribute values and stuck them in 'td' elements.

For reasons which aren't very interesting, I now sometimes need to
handle output where one (or more) of those attribute values
_shouldn't_ be put into a table cell.  For example, using the result
fragment above, I might not want to output the 'Duration' attribute
values.  The XML input always has some header metadata that defines,
among other things, exactly this---which columns are to be formatted
into the HTML output, and how to pretty-print their names, and so on.
So, to continue the example, I may have in the same input these column
descriptions:

  <outcomes:columns>
    <outcomes:column attName="Computer" displayName="Computer Used" sum="no" /> 
    <outcomes:column attName="Location" displayName="The Location" sum="no" /> 
  </outcomes:columns>

That is, from the 'row' elements, I only want to use attributes
'Computer' and 'Location', not 'Duration'.

Now, that's the preamble.  Here's the question.  My current solution
looks a little O(n^2) to me:

  <xsl:for-each select="@*">
    <xsl:variable name="thisName" select="name()"/>
    <xsl:variable name="thisValue" select="."/>
    <xsl:for-each select="/outcomes:report/outcomes:header/outcomes:table/outcomes:columns/outcomes:column">
      <xsl:if test="@attName = $thisName">
        <td>
          <xsl:value-of select="$thisValue"/>
        </td>
      </xsl:if>
    </xsl:for-each>
  </xsl:for-each>

(This fragment is inside the template matching 'row'.)  That is, for
every attribute in a 'row', check every element in the collection of
'outcomes:column' elements to see if its 'attName' matches.

It does not seem to be creating any huge performance hit, but is there
a more elegant way to code this (preferably without changing the
input)?


-- 
Paul.

w  http://logicsquad.net/
h  http://paul.hoadley.name/

Current Thread