Re: Variable number of attributes
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()))] 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()))]" /> 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
PURCHASE STYLUS STUDIO ONLINE TODAY!
Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!
Download The World's Best XML IDE!
Accelerate XML development with our award-winning XML IDE - Download a free trial today!
Subscribe in XML format