- Create templates that match the attributes in question.
- Apply templates to the attributes.
- That's all.
Something like this:
<xsl:template match="f28">
<xsl:apply-templates select="ROW" />
</xsl:template>
<xsl:template match="ROW">
<xsl:apply-templates select="@*">
<xsl:sort select="name()" />
</xsl:apply-templates>
</xsl:template>
<!-- @f1 becomes <hasTestDegree> -->
<xsl:template match="f28//@f1">
<hasTestDegree>
<xsl:value-of select="." />
</hasTestDegree>
</xsl:template>
<!-- add more templates for the other attributes... -->
<!-- any attribute with a value of 'NULL' is not output -->
<xsl:template match="@*[. = 'NULL']" />
Notes.
- It seems unnecessary to use
<xsl:element>
in your case, just write out the element you want to create. - My solution relies on match specificity. The match expression
@*[. = 'NULL']
overrulesf28//@f1
for attributes that are'NULL'
. - The intermediate step (
<xsl:apply-templates select="ROW" />
) is necessary to make sure everything is processed in the right order. - You could either use
<xsl:sort>
in<xsl:apply-templates>
or use<xsl:apply-templates>
several times in a row, if you want to determine output order manually.