Mismatched TR elements killing me

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Mismatched TR elements killing me

 before the even elements and ending a  after the odd elements.  There is a SaxParseException when I do this complaining about the tags not matching:

org.xml.sax.SAXParseException: The element type "tr" must be terminated by the matching end-tag "".

The thing is, the template logic would work exactly as I desire if I could just tell the parser to stow it.  I know this because when I surround my  and  tags in comments, the output is exactly as I would desire (save that they are surrounded in comment).

There is a bit of template code to account for the case where there are an odd number of elements in the list and hence the TR tag needs to be closed.  I have tried setting the different TemplateModes on the TemplateResolver to no avail.  Here is the template code:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Play1</title>
</head>

<body>
Eric Minor
Sorry if this is newbie, but I'm spinning my wheels on it for too long.  I have a list of "affiliations" (IE persons for the most part) maybe 3 or 4 or 5 long.  I desire to list 2 people per row in a table.  I'd like to be able to iterate the list, starting a
    <th:block th:each="newEa : ${data.newAffiliations}" >   
 
    <th:block th:switch="${newEaStat.even}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>     
 
       
    <th:block th:switch="${newEaStat.odd}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>   
   
    <th:block th:switch="${newEaStat.last}"> 
      <th:block th:case="true">
        <th:block th:switch="${newEaStat.even}"> 
          <th:block th:case="true">
                                  </th:block>
        </th:block>     
      </th:block>
    </th:block>
  </th:block>   

      John Doe
   
 
</body>
</html>

Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

 within the case="true" section.

    <th:block th:switch="${newEaStat.even}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>     
Eric Minor
Well...the code of the template did not display the way I pasted it in.  I'll try another small block here...there is a
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
Nope...this client does not display my pasted code correctly...not sure how to communicate my problem.
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
In reply to this post by Eric Minor
Another attempt at posting a simplified version of the code:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Play1</title>
</head>

<body>
    <th:block th:each="newEa : ${data.newAffiliations}" >     
    <th:block th:switch="${newEaStat.even}"> 
          </th:block>     
 
       
    <th:block th:switch="${newEaStat.odd}"> 
          </th:block>   
  </th:block>   
      John Doe
   
  </body>
</html>
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Zemi
Administrator
Hello,

you can paste code in this forum inside raw tags.

Regards,
  Zemi

Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
Ahhh...wasn't aware of "raw".  The raw enclosed code is pasted below.

[raw]

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Play1</title>
</head>

<body>

 Play1


    <th:block th:each="newEa : ${data.newAffiliations}" >   
 
   
    <th:block th:switch="${newEaStat.even}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>     
 
       
   
    <th:block th:switch="${newEaStat.odd}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>   
   
     
    <th:block th:switch="${newEaStat.last}"> 
      <th:block th:case="true">
        <th:block th:switch="${newEaStat.even}"> 
          <th:block th:case="true">
                                  </th:block>
        </th:block>     
      </th:block>
    </th:block>
  </th:block>   

      John Doe
   
 
</body>
</html>


[/raw]
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
In reply to this post by Eric Minor
[raw]

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Play1</title>
</head>

<body>

 Play1


    <th:block th:each="newEa : ${data.newAffiliations}" >   
 
   
    <th:block th:switch="${newEaStat.even}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>     
 
       
   
    <th:block th:switch="${newEaStat.odd}"> 
      <th:block th:case="true">
              </th:block>
    </th:block>   
   
     
    <th:block th:switch="${newEaStat.last}"> 
      <th:block th:case="true">
        <th:block th:switch="${newEaStat.even}"> 
          <th:block th:case="true">
                                  </th:block>
        </th:block>     
      </th:block>
    </th:block>
  </th:block>   

      John Doe
   
 
</body>
</html>


[/raw]
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
I give up...
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

danielfernandez
Administrator
Never do ;)

Thymeleaf's parser is complaining about your code because what is parsing is not the output of your execution, but your template itself, and:

<th:block ...>
   <tr>
</th:block>

...is actually invalid code (from the XML perspective of Thymeleaf's parsers), given you are opening a <tr> inside that <th:block> and never closing it. So you need to convert your template into hierarchically-valid markup.

The first solution that comes out of my mind is to use #numbers.sequence(from,to,step) in oder to create the sequence that will actually drive your iteration, given you want two elements per row. So:

<tbody th:with="affils=${data.newAffiliations}, affilsLen=${affils.length()}">
  <tr th:each="i : ${#numbers.sequence(0, affilsLen, 2)}">
    <td th:with="newEa=${affils[i]}">
      <span th:text="${newEa.name}">...</span>
    </td>
    <td th:with="newEa=((i + 1) < affilsLen ? ${affils[i + 1]}">
      <span th:text="newEa ? ${newEa.name}">...</span>
    </td>
  </tr>
</tbody>

More info about the #numbers expression utility object here: http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#numbers

Hope this helps. And also hope my code works, because I've written it directly from memory :-)

Regards,
Daniel.



Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

danielfernandez
Administrator
Oh, and by the way: the way to insert arbitrary code in Nabble forums like this is inside <raw> elements :)
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
In reply to this post by danielfernandez
Thanks for the pointer and it got me to something that finally worked.  The syntax in the 2nd td element would not work for me despite trying about 30 variations of where parentheses and braces went (looks like you had a rogue parenthesis in your from-memory code).  I ended up having to brute-force the 2nd td with a switch.  We will see if my raw tags do the trick this time.  Also FYI to others I had to change affils.length() to affils.size().


<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Play1</title>
</head>

<body>
<h1> Play1 </h1>

<table border="1">
<tbody th:with="affils=${data.newAffiliations}, affilsLen=${affils.size()}">
  <tr th:each="i : ${#numbers.sequence(0, affilsLen-1, 2)}">
    <td th:with="newEa=${affils[i]}">
      <span th:text="${newEa.firstName} + ' ' + ${newEa.lastName}">John Doe</span>
    </td>
    
    <th:block th:switch="${i+1} &lt; ${affilsLen}"> 
      <th:block th:case="true">
        <td th:with="newEa=${affils[i+1]}">
          <span th:text="${newEa.firstName} + ' ' + ${newEa.lastName}">John Doe</span>
        </td>
      </th:block>
      <th:block th:case="*">
        <td>
        </td>
      </th:block>
    </th:block>               
  </tr>
</tbody>
</table>
  
</body>
</html>

Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Emanuel
Administrator
This post was updated on .
A bit late now that you've got a solution, but if your page is going to be displayed in any browser that supports the CSS flexbox model (http://caniuse.com/#search=flex) then another solution might be to use CSS flexbox to lay out those items.  eg: create sections that fit all the affiliations in them, making sure they can only fit 2 items across.  Then, using flexbox rules, make it so that items flow correctly within those sections.

CSS Flexbox tutorial: http://css-tricks.com/snippets/css/a-guide-to-flexbox/

I think a lot of the questions in this forum about laying things out in a specific way across a table can be solved by using a simpler non-table HTML structure and/or some smart CSS :)

---
EDIT: Actually, I think this one can be done without even using flexbox.  If you just make the affiliate elements a width relative to the parent container, say 50%, then the document flow will push the next affiliates down.  Boom! :D
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Eric Minor
Thanks for the tip, but this is actually for emails, not web.  Our email team tells me that, from their experience, it is important to use older table/tr/td layout in order to get passable rendering results from the large variety of email clients out there.

I hate to say it, but something like Velocity may be an easier path for us.  It isn't terribly important to me that the template be well formed XML, though I certainly do prefer that the output of the template merge be well formed.  The most important consideration is probably that the templates be as simple and straight-forward as possible.  While waiting to hear back on a Thymeleaf solution in this forum, I did try it with Velocity in order to have a fallback position...the snippet below did what I needed in a very straight-forward way.

Can anyone shed light for me as to whether having the template be well formed XML should be an important consideration for me?  Is there any way to tell Thymeleaf to relax and turn off validation on the input template (but maybe make sure the output is well formed)?

#foreach( $newAffiliation in $data.newAffiliations )
  #if ($foreach.index%2 == 0)
    <tr>
  #end
  
  <td>
    $newAffiliation.firstName $newAffiliation.lastName
  </td> 
   
  #if ($foreach.index%2 == 1)
    </tr>
  #end
  
  #if ($foreach.index%2 == 0 && !$foreach.hasNext)
    <td></td>
    </tr>
  #end  
#end
Reply | Threaded
Open this post in threaded view
|

Re: Mismatched TR elements killing me

Emanuel
Administrator
> this is actually for emails, not web

Ah, missed that detail.  You're right to listen to your e-mail team as using the older layout methods (tables and such) is the current wisdom for reaching a wider variety of e-mail clients.

As for whether having well-formed XML is an important consideration: that's entirely up to you.  Thymeleaf is built atop an XML parser, so it needs well-formedness to work (this will no longer be the case w/ Thymeleaf 3, but that's still a way off).  There is a relaxing template mode option (set the templateMode property to "LEGACY_HTML5") which then needs the tag balancer library dependency of nekoHTML to run.

If you find Velocity is better for you in this case, then by all means use Velocity.  It's good to see developers spend time to evaluate their options before settling on a solution :)