112

In XSLT there is the

<xsl:value-of select="expression"/>

to get the value of an element, but is there something to select the tag-name of the element?

In a situation like this:

<person>
  <!-- required stuff -->
  <name>Robert</name>
  <!-- optional stuff, free form for future extension. 
       Using XMLSchema's xsd:any -->
  <profession>programmer</profession>
  <hobby>photography</hobby>
</person>

<xsl:for-each select="person">
   <xsl:tag-of select="."/> : <xsl:value-of select="."/>
</xsl:for-each>

To get output like this:

name : Robert
profession : programmer
hobby : photography

Of course the above XSLT won't compile because

 <xsl:tag-of select="expression"/>

doesn't exist. But how could this be done?

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Robert Gould
  • 68,773
  • 61
  • 187
  • 272
  • The most relevant tag for this question is XPath. Both functions are XPath standard functions and can be used within an XPath expression in the context of any hosting language (C#, XSLT, XQuery, ...) Please, re-tag – Dimitre Novatchev Feb 25 '09 at 17:09
  • This text: "In XSLT there is the " -- contains an error. The usually used prefix for XSLT instructions is "xsl". Usually when using XML Schema we use the prefix "xsd" or "xs". Please, correct. – Dimitre Novatchev Feb 25 '09 at 20:17

6 Answers6

172

This will give you the current element name (tag name)

<xsl:value-of select ="name(.)"/>

OP-Edit: This will also do the trick:

<xsl:value-of select ="local-name()"/>
Robert Gould
  • 68,773
  • 61
  • 187
  • 272
Rashmi Pandit
  • 23,230
  • 17
  • 71
  • 111
111

Nobody did point the subtle difference in the semantics of the functions name() and local-name().

  • name(someNode) returns the full name of the node, and that includes the prefix and colon in case the node is an element or an attribute.
  • local-name(someNode) returns only the local name of the node, and that doesn't include the prefix and colon in case the node is an element or an attribute.

Therefore, in situations where a name may belong to two different namespaces, one must use the name() function in order for these names to be still distinguished.

And, BTW, it is possible to specify both functions without any argument:

name() is an abbreviation for name(.)

local-name() is an abbreviation for local-name(.)

Finally, do remember that not only elements and attributes have names, these two functions can also be used on PIs and on these they are identical).

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
15
<xsl:for-each select="person">
  <xsl:for-each select="*">
    <xsl:value-of select="local-name()"/> : <xsl:value-of select="."/>
  </xsl:for-each>  
</xsl:for-each>
bluish
  • 26,356
  • 27
  • 122
  • 180
Ray Lu
  • 26,208
  • 12
  • 60
  • 59
  • As a good practice always use normalize-space() when getting value-of the node This will trim the extra spaces – Rashmi Pandit Feb 25 '09 at 11:28
  • Such normalisation/sanitisation would only be needed if it hadn't been handled at the input gathering stage. Doing it then saves having to do it at access time, which is usually far more often. One would do it before adding to an RDB, and an xml document is just another database. – Patanjali Feb 14 '18 at 03:56
9

For those interested, there is no:

<xsl:tag-of select="."/>

However you can re-create the tag/element by going:

<xsl:element name="{local-name()}">
  <xsl:value-of select="substring(.,1,3)"/>
</xsl:element>

This is useful in an xslt template that for example handles formatting data values for lots of different elements. When you don't know the name of the element being worked on and you can still output the same element, and modify the value if need be.

Tim
  • 966
  • 1
  • 13
  • 22
6
<xsl:value-of select="name(.)" /> : <xsl:value-of select="."/>
bluish
  • 26,356
  • 27
  • 122
  • 180
Rowland Shaw
  • 37,700
  • 14
  • 97
  • 166
  • So why'd this get down voted? Granted could've mentioned local-name() if you didn't want the namespace as well, but it would be useful to the wider community to explain why this wouldn't work. – Rowland Shaw Feb 25 '09 at 12:30
  • Perhaps, it couldn't transform the given XML. the name(.) will be "person" in this case. it should be "name", "profession" and "hobby". – Ray Lu Feb 25 '09 at 19:50
  • @CodeMelt Why then you didn' downvote the accepted answer? It good, but is even less specific than this one. I up-voted Rowland Shaw's answer as it provides the answer to the question. Plese, downvote only when an aswer contains wrong, incorrect or misleading information – Dimitre Novatchev Feb 25 '09 at 20:22
  • 4
    Fixed that minor detail - personally, i think that people should explain why something is downvoted, as it helps explain the collective knowledge... – Rowland Shaw Feb 25 '09 at 21:53
  • Our reputations may attract attention, but as they are no guarantee that what we have posted is worthwhile, it is the quality of our contribution that really counts. No reasoning makes for poor quality contributions. – Patanjali Feb 14 '18 at 03:48
0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:template match="person">
        <xsl:for-each select="*">
            <xsl:text>
       </xsl:text>
            <xsl:value-of select="local-name()"/> : <xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>