Reputation: 583
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
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
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