[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Variable number of attributes

Subject: Re: Variable number of attributes
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Tue, 03 Oct 2000 09:54:55 +0100
xsl variable number
At 12:53 30/09/00 -0400, John E. Simpson wrote:
> [a solution to a problem involving a table of attributes]

It's worth noting that there could be a problem if the attributes are in
different orders for different elements.  The attribute:: axis goes through
the attributes in document order: if these are different for different
elements, then the attribute values will end up in the wrong cells.  It's
easy to get around this by sorting the attributes by name within the
xsl:for-eaches:

  <xsl:for-each select="@*">
    <xsl:sort select="name()" />
    <td><xsl:value-of select="."/></td>
  </xsl:for-each>

It's usually worth doing this because there's no automated way to check
whether attributes occur in a particular order (validation won't tell you)
and it's perfectly legal for a (multi-threaded) XML parser to go through
them in whatever order it wants - attributes are by definition unordered.

>(1) The below works as long as the <ele> elements each has the same number 
>of attributes, with the same names. If one <ele> has 4 attributes and one 
>has 3, for example, then it will break.

It will also break if different elements have different combinations of
attributes, e.g.:

<ele name1="A1" name2="A2" />
<ele name2="B2" name3="B3" />

Here, there are three attributes in total, but only two per element.

When you take this into account, the problem becomes one of firstly
identifying what uniquely named attributes there are within the XML source,
and then, for each element, emitting the value of the attributes in the
same order.

Identifying uniquely named attributes just involves a Muenchian approach -
defining a key that indexes on attribute name to group the attributes:

<xsl:key name="attrs" match="ele/@*" use="name()" />

and then finding those attributes that are first in the set returned by the
key for that particular name:

  /doc/ele/@*[generate-id() = generate-id(key('attrs', name())[1])]

These attributes can be stored in a (global) variable for future reference:

<xsl:variable name="attrs"
              select="/doc/ele/@*[generate-id() =
                                  generate-id(key('attrs', name())[1])]" />

Creating the header row is then a matter of cycling over these attributes
and giving their names:

<xsl:for-each select="$attrs">
  <th><xsl:value-of select="name()"/></th>
</xsl:for-each>

The body of the table involves cycling over these attributes as well, in
order to get the right number and right order for the cells, but this time
getting the value of the attribute on the 'ele' element you're interested
in.  Iterating over the attributes is easy:

<xsl:template match="ele">
  <tr>
    <xsl:for-each select="$attrs">
      <td>...</td>
    </xsl:for-each>
  </tr>
</xsl:template>

But within the xsl:for-each, the current node will be one of those
attributes, not the 'ele' element.  This means that you have to set a
variable to hold a reference to the 'ele' element so that you can access
the value of the relevant attribute within the xsl:for-each:

<xsl:template match="ele">
  <xsl:variable name="ele" select="." />
  <tr>
    <xsl:for-each select="$attrs">
      <td>...</td>
    </xsl:for-each>
  </tr>
</xsl:template>

The value that you want within the cell is then the value of the attribute
of the $ele element that has the same name as the name of the current node
(the attribute in $attrs that you're currently on):

<xsl:template match="ele">
  <xsl:variable name="ele" select="." />
  <tr>
    <xsl:for-each select="$attrs">
      <td><xsl:value-of select="$ele/@*[name() = name(current())]" /></td>
    </xsl:for-each>
  </tr>
</xsl:template>

I've tested this approach and it works in SAXON and Xalan.

This level of complexity is completely unnecessary for the problem as it
was phrased, but it demonstrates how much XSLT stylesheets are dependent on
assumptions that are made about the XML source that they're expected to
encounter.

Cheers,

Jeni

Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.