Xml – Selecting node sets (attributes or elements) which match a string variable name

xmlxpathxslt

Consider this simple xml element example:

<parent foo="1" bar="2" foobar="3">
    <child/>
</parent>

In the xsl file, I am in the context of "parent" (i.e. within the <template match="parent">). I want to select a node set (in the example, only one attribute) based upon a string variable. For example i want to select a node-set which matches $attribute-name. I'll show my failed xsl example and you will probably understand what i'm trying to do.

<xsl:template match="parent">
    <xsl:call-template name="print-value-of">
        <xsl:with-param name="attribute-type" select="'foo'"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="print-value-of">
    <xsl:param name="attribute-type"/>

    <xsl:value-of select="$attribute-type"/>
</xsl:template>

This prints the output:

foo

What I first INTENDED it to do (but I realize that this is not what it should do) is:

  1. evaluate the variable attributetype (or param, if you want to be picky) as the string 'foo'
  2. call the value-of as if I had called <xsl:value-of select="foo"/>

I.e. what I wanted it to print was:

1

THE QUESTION: How can I achieve this behaviour?

Notice: I am aware of the fact that I, in this simple case, could pass the actual attribute node as a parameter (i.e. <xsl:with-param name="attribute" select="foo"/>). But that is not the solution I am searching for. I need to pass only information about the attribute type (or attribute name if you'd prefer to call it that)

What I am actually trying to do is creating a general function template which can:

  1. Call a function (call-template) with the attribute-type as a parameter
  2. In the function do a bunch of operations which give me a node set, stored in a variable
  3. sum all of the attributes of the elements in the node set, which are of the previously selected attribute-type

<EDIT>
I can only use XSLT 1.0, so 1.0 solutions are much preferred!
</EDIT>

<EDIT2>

A follow-up question on a similar theme: Is it also possible to create attributes of a with the name/type specified by a string variable? I.e.

<xsl:attribute name="$attribute-type"/>

Doing it like the line above results in $attribute-type being the literal name of the attribute in the xml output. Instead I would like it, again it to evaluate the variable and give the evaluated value as the name.
</EDIT2>

Best Answer

This selects an attribute with the name of 'foo'.

<xsl:call-template name="print-value-of">
  <xsl:with-param name="attribute-type" select="@*[name() = 'foo']"/>
</xsl:call-template>

<xsl:template name="print-value-of">
   <xsl:param name="attribute-type"/>
   <xsl:value-of select="."/>
</xsl:template>

Alternatively, you can leave the <xsl:call-template> like it is and do the change in your template:

<xsl:template name="print-value-of">
  <xsl:param name="attribute-type"/>

  <xsl:value-of select="@*[name() = $attribute-type]"/>
</xsl:template>

In any case, unless this was only a synthetic example, all of the above is a quite expensive way of saying:

<xsl:value-of select="@*[name() = $attribute-type]"/>

EDIT:

To create attributes with a dynamic name, use:

<xsl:attribute name="{$attribute-type}">
  <xsl:value-of select="$some-value-or-expression" />
</xsl:attribute>

Note that the curly braces make the XSLT-processor evaluate their contents (in attribute values only).

You should make sure that $attribute-type contains a string that adheres to the XML naming rules. And you should think about renaming the variable to $attribute-name, because that's what it is.

Related Topic