Encephalon
Encephalon

Reputation: 153

XSL Repeating Same XML Element/Node, Not Working Correctly

So this is what my XML looks like. It's pretty darn simple, just want to lay out a bunch of links to other XML files with different names/titles for each link of course:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<playToc>
    <play>a_and_c.xml</play>
    <play>all_well.xml</play>
    <play>as_you.xml</play>
    <play>com_err.xml</play>
    <play>coriolan.xml</play>
    <play>cymbelin.xml</play>
    <name>Title 1</name>
    <name>Title 2</name>
    <name>Title 3</name>
    <name>Title 4</name>
    <name>Title 5</name>
    <name>Title 6</name>
</playToc>

Pretty simple, right? And so here is my XSL:

<?xml version="1.0" encoding="ISO-8859-1"?>

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

<xsl:template match="playToc">
<html>
<body style="text-align:center;">

<xsl:apply-templates select="play"></xsl:apply-templates>

</body>
</html>
</xsl:template>

<xsl:template match="play">

<xsl:variable name="URL">
    <xsl:value-of select="."/> 
</xsl:variable>

<xsl:variable name="TITLE">
    <xsl:value-of select="../name"/> 
</xsl:variable>

<a href="{$URL}"><xsl:value-of select="$TITLE"/></a>
<br />
</xsl:template>

</xsl:stylesheet>

And this is the output:

Title 1
Title 1
Title 1
Title 1
Title 1
Title 1

When I want this to be the output, of course:

Title 1
Title 2
Title 3
Title 4
Title 5
Title 6

Any help would be so great! Thanks a bunch!

Upvotes: 1

Views: 1270

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243579

<xsl:variable name="TITLE">      
 <xsl:value-of select="../name"/>   
</xsl:variable>

Your problem is here.

The string value of ../name is the string value of the first name child of the parent of the initial context (current) node.

What you actually want is to get the value of the name child that has the same position as the position of the current (play) node.

This complete and short transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="play">
   <xsl:variable name="vPos" select="position()"/>
     <a href="{.}">
      <xsl:value-of select="../name[$vPos]"/>
     </a><br />
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

when applied on the provided source XML document:

<playToc>
    <play>a_and_c.xml</play>
    <play>all_well.xml</play>
    <play>as_you.xml</play>
    <play>com_err.xml</play>
    <play>coriolan.xml</play>
    <play>cymbelin.xml</play>
    <name>Title 1</name>
    <name>Title 2</name>
    <name>Title 3</name>
    <name>Title 4</name>
    <name>Title 5</name>
    <name>Title 6</name>
</playToc>

produces the wanted, correct result:

<a href="a_and_c.xml">Title 1</a>
<br/>
<a href="all_well.xml">Title 2</a>
<br/>
<a href="as_you.xml">Title 3</a>
<br/>
<a href="com_err.xml">Title 4</a>
<br/>
<a href="coriolan.xml">Title 5</a>
<br/>
<a href="cymbelin.xml">Title 6</a>
<br/>

Do note:

  1. There is no need to use xsl:apply-templates at all.

  2. There is just one template.

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167716

Well the XML input is poorly structured but you can work around this by doing

<xsl:template match="play">
  <xsl:variable name="pos" select="position()"/>
  <a href="{.}">
    <xsl:value-of select="../name[position() = $pos]"/>
  </a>
  <br/>
</xsl:template>

Make sure you keep the <xsl:apply-templates select="play"/> in the other template, otherwise the approach with position() won't work.

Upvotes: 2

Related Questions