Guilhermeffable
Guilhermeffable

Reputation: 521

xsl:for-each only returns the first node

I'm having some troubles with XSLT. I want to output each subs property from this

<subscritores>
  <subs ref="Guicky"/>
  <subs ref="Daisy"/>
</subscritores>

Basically my problem is that xsl:for-each is only getting me the first attribute @subs. And I have the same problem with the administradores/@ref

<administradores>
  <admin ref="Guicky"/>
  <admin ref="Daisy"/>
</administradores>

This is my XML code:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
  <!DOCTYPE xml_tube SYSTEM 
       "C:tp2\Um utilizador\Utilizador\xml__tube.dtd">    
  <?xml-stylesheet type="text/xsl" href="utilizadorG.xsl" ?> 
    
  <xml_tube>
    <playlist>
      <lista owner="Guicky" dataIns="2016-10-24" id="PV1">
        <titulo>BEST MUSIC.</titulo>
        <descricao>Compilation of my favourite music videos.</descricao>
        <gostosL gostouL="Guicky"/>
        <links_vid vid="Vid2"/>
        <links_vid vid="Vid3"/>
        <administradores>
          <admin ref="Guicky"/>
          <admin ref="Daisy"/>
        </administradores>
        <editores>
          <editor ref="Guicky"/>
        </editores>
        <subscritores>
          <subs ref="Daisy"/>
          <subs ref="Anabela65"/>
        </subscritores>
      </lista>
      <lista owner="Anabela65" dataIns="2016-02-29" id="PV2">
         <titulo>Cooking Lessons!</titulo>
         <descricao>Cooking lesson's with Guicky's mom!</descricao>
         <links_vid vid="Vid4"/>
         <administradores>
           <admin ref="Anabela65"/>
           <admin ref="Guicky"/>
         </administradores>
         <editores>
           <editor ref="Anabela65"/>
         </editores>
         <subscritores>
           <subs ref="Guicky"/>
           <subs ref="Daisy"/>
         </subscritores>
      </lista>
    </playlist>
    <comentarios>
      <comentario id="C1" refV="Vid1" user="Guicky" data="2016-10-23">
        <text>AHAHAHAHA, bom vídeo.</text>
        <gosto gostou="Daisy"/>
        <respostas>
          <texto autor="Daisy">Grande clássico!</texto>
        </respostas>
      </comentario>
      <comentario id="C2" refL="Vid2" user="Anabela65" data="2016-10-22">
        <text>Timmy timmy timmy turner...</text>
        <gosto gostou="Guicky"/>
        <gosto gostou="Daisy"/>
        <respostas>
          <texto autor="Guicky">U know it.</texto>
          <resposta autor="Daisy">LOL!</resposta>
        </respostas>
      </comentario>
    </comentarios>
  </xml_tube>`

This is my XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:output doctype-public="-//W3C//DTD XHTML 1.1//EN"
            doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />
                   
<xsl:template match="/">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="eng">
    <head>
     <title>My XML Tube</title>
     <link rel="stylesheet" type="text/css" href="XML_Tube.css" charset="UTF-8"/>
    </head>
    <body>
      <h1 id="lala">Playlists</h1>
      <section>
        <xsl:for-each select="xml_tube/playlist/lista">
          <article class="list">
            <figure>
              <xsl:element name="img">
                <xsl:attribute name="src">
                  <xsl:value-of select="thumbnail/@link"/>
                </xsl:attribute>
                <xsl:attribute name="width">50%</xsl:attribute>
                <xsl:attribute name="height">auto</xsl:attribute>
              </xsl:element>
              <figcaption>
 <a href="https://goo.gle"><xsl:value-of select="titulo"/></a>
 <p>Nome de utilizador:<xsl:value-of select="@owner"/></p>
 <p>Descrição:<xsl:value-of select="descricao"/></p>
 <p>Admin:   <xsl:value-of select="administradores/admin/@ref"/></p>
 <p>Editores: <xsl:value-of select="editores/editor/@ref"/></p>
 <p>Subscritores:<xsl:value-of 
                               select="subscritores/subs/@ref"/>
     <xsl:text></xsl:text></p>
              </figcaption>
            </figure>
          </article>
        </xsl:for-each>
      </section>
    </body>
   </html>
  </xsl:template>
 </xsl:stylesheet>

I'm portuguese and this is part of a school work, I didn't had time to translate every single node, but I think that shouldn't be a problem. Anyway, thanks in advance!

My expected output is:

Subscritores: Daisy
Subscritores: Anabela

Upvotes: 2

Views: 1467

Answers (2)

surfmuggle
surfmuggle

Reputation: 5942

I had the same problem that only one element was rendered. In my case i wanted to output

  • the attributes method, result and time
  • from every <test>-element inside <collection ...> .... </collection>

This xml file based on xunit test execution result is the input file

<assemblies timestamp="02/15/2023 13:30:45">
  <assembly name="C:\dev\*.Tests.dll" 
            run-date="2023-02-15" 
            run-time="13:30:45" total="2" passed="2" failed="0" 
            skipped="0" time="1.890" errors="0">
    <errors />
    <collection total="2" passed="2" failed="0" skipped="0" 
                name="Test collection ..." time="0.537">
      <test 
            name="LoginTest.LoginFailure" 
            type="Tests.LoginTest"  
            method="LoginFailure"  
            result="Pass"
            time="0.3675186">
        <traits />
      </test>
      <test 
            name="LoginTest.LoginSuccess" 
            type="Tests.LoginTest" 
            method="LoginSuccess"  
            result="Pass"
            time="0.1698593">
        <traits />
      </test>
    </collection>
  </assembly>
</assemblies>

After i solved Unsafe attempt to load URL i had to find out how to render attributes of an element. Michaels answer helped me to write this. As you can see the attributes can be rendered with <xsl:value-of select="@attributeName" />

<?xml version="1.0" encoding="UTF-8"?>

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

<xsl:template match="/">
  <html>
  <body>
.....
<xsl:for-each select="assemblies/assembly/collection/test">       
<tr>               
 <td><xsl:value-of select="@method" /></td>
 <td><xsl:value-of select="@result" /></td>      
 <td><xsl:value-of select="@time" /></td>            
</tr>
</xsl:for-each>
....
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

And this is the result

xml-xsl-html-output

Upvotes: 0

michael.hor257k
michael.hor257k

Reputation: 116959

In XSLT 1.0 - which is apparently what you're using - the xsl:value-of instruction returns the value of only the first node in the selected node-set.

If you want to list all the values, you need to get them one-by-one: e.g. instead of:

<xsl:value-of select="administradores/admin/@ref"/>

use:

<xsl:for-each select="administradores/admin">
    <xsl:value-of select="@ref" />
    <xsl:text> </xsl:text>
</xsl:for-each> 

Upvotes: 2

Related Questions