Vladyn
Vladyn

Reputation: 583

xsl:for-each Getting the current() node attribute

I have a question about xsl:for-each loop:

I have something like

<hodeName>
    <nodeChild name='name1'>value</nodeChild>
    <nodeChild name='name2'>value</nodeChild>
    <nodeChild name='name3'/>
</hodeName>

I want to loop over them, name a variable with attribute name and assign it the value. I'm struggling with something like

<xsl:for-each select="/root/nodeName">
    <json:string name="{current()/@name}"><xsl:value-of select="current()" /></json:string>
</xsl:for-each>

Which doesn't work. It is assigning however the correct xsl:value-of.

Upvotes: 2

Views: 5914

Answers (2)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

Why your approach does not work

You are defining a sequence to be processed by for-each like the following:

<xsl:for-each select="/root/nodeName">

But if you compare this to your input XML, there is no outermost element that is called root. The outermost element is called hodeName. Perhaps you thought /root was a special keyword in XSLT to refer to the root of the document? That's not the case. root is just a normal XML element. / itself, when at the beginning of an XPath expression, means the root or document node.


Another approach would use several templates instead of for-each. "Looping over" something is a concept more related to procedural languages, not declarative, functional languages like XSLT. Applying templates is the XSLT-onic (perhaps you know Python?) way of doing it.

Are you sure the outermost element should be called hodeName instead of nodeName?

Stylesheet

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
   xmlns:json="http://json.org/">

   <xsl:output method="xml" indent="yes"/>
   <xsl:strip-space elements="*"/>          

   <xsl:template match="hodeName">
       <json:object>
           <xsl:apply-templates/>
       </json:object>
   </xsl:template>

   <xsl:template match="nodeChild">
       <json:string name="@name">
           <xsl:value-of select="."/>
       </json:string>
   </xsl:template>

</xsl:stylesheet>

XML Output

<?xml version="1.0" encoding="utf-8"?>
<json:object xmlns:json="http://json.org/">
   <json:string name="@name">value</json:string>
   <json:string name="@name">value</json:string>
   <json:string name="@name"/>
</json:object>

Upvotes: 1

Markus Jarderot
Markus Jarderot

Reputation: 89181

You are selecting /root/nodeName instead of /hodeName/nodeChild as your XML suggests. Otherwise it seems to work.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:json="http://json.org/"
                version="1.0">
   <xsl:template match="/">
     <json:object>
       <xsl:for-each select="/hodeName/nodeChild">
         <json:string name="{current()/@name}"><xsl:value-of select="current()" /></json:string>
       </xsl:for-each>
     </json:object>
   </xsl:template>
</xsl:stylesheet>

Also, you don't need to specify current() unless it is the only expression. @name is equivalent to current()/@name.

Upvotes: 3

Related Questions