The syntax looks like this
<items :{ item | <item> }>
Putting it together in Java:
List<String> teams = Arrays.asList("Cats", "Birds", "Turtles"); ST s = new ST( "<teams :{team | <team> }>"); s.add("teams", teams); System.out.println(s.render());
In this example, I iterate over the List and print each team that is on the teams list. The result to be printed:
Cats Birds Turtles
We can learn the syntax that makes this possible. Before we do this, remember that the default delimiters in a StringTemplate are less than < and greater than > . Since we did not specify another separator < > , we will use it in our example. More about separators
:{ }
This character set, a colon : and the open and closed braces {} can be read as "for everyone." In the sample template, the code reads for each team in teams print team . Left side of a vertical pipe | indicates the variable that will be created for each iteration. It will keep the current command from the list of commands. The seal consists of <team> on the right side of the vertical pipe | and the left side of the closing bracket } . Everything on the right side of the vertical pipe | and before closing the base } will be evaluated for printing.
:{ current value | everything in here will be printed }
To develop this concept, let's use a more complex data structure.
public class Player { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public int getAge() { return age; } public String getName() { return name; } }
Now we can create several players for our team:
Player[] players = new Player[] { new Player("Bill", 29), new Player("Steve", 30), new Player("Toby", 15) }; String playerTemplate = "<players:{ player |<player.name> is <player.age> <\\n>}>" ST s = new ST( playerTemplate ); s.add("players", Arrays.asList(players)); System.out.println(s.render());
To give a result
Bill is 29 Steve is 30 Toby is 15
A few things to note. We did not directly access the age and property name. ST called the getAge and getName methods. ST does not look at properties. Instead, he is looking for access methods.
What if we just wanted to iterate over a list containing another list. We can do it as well. First, let's create our data structure and populate it with a few lists.
List<List<String>> listOfLists = asList( asList("One", "Two", "Three"), asList("Four", "Five"), asList("Six", "Seven", "Eight", "Nine") );
The template will look as follows.
<list :{ items |<items :{ item |<item> }><\n>}>
Our template, in this case, will be just a combination. The outer shell will iterate over the list that we will pass.
<list :{ items | what we will print }>
Then, for each item, we print the items in our list.
<items :{ item |<item> }>
Once we put it all together
String template = "<list :{ items |<items :{ item |<item> }><\\n>}>"; ST st = new ST( template); st.add("list", listOfLists); System.out.println(st.render());
We get a result that looks like this.
One Two Three Four Five Six Seven Eight Nine
Based on this concept a little more, we can create a second data structure that contains a list of players. This will show how to iterate inside an iteration.
The first thing we need is a data structure that contains a list. To do this, we can create a Team in which our players will participate.
public class Team { private List<Player> players; private String name; public Team (String name, List<Player> players) { this.players = players; this.name = name; } public List<Player> getPlayers() { return players; } public String getName() { return name; } }
Please note that there are players in our team. This composition will allow us to build two iterations.
Now that we have the data structure, let's put it all together to create a couple of teams with several players.
List<Team> teams = asList( new Team("Billings", asList( new Player("Bill", 29), new Player("Steve", 30), new Player("Toby", 15) )), new Team("Laurel", asList( new Player("Chad", 32), new Player("Chuck", 29), new Player("Will", 24), new Player("Ben", 26) )) );
Now let's create a template and fill in a few details:
String simpleTeamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>}>"; ST template = new ST( simpleTeamTemplate ); template.add("teams", teams); System.out.println(template.render());
It will print
Billings has 3 players Laurel has 4 players
Our simple template is about the same as our first template on top. The only real difference is that we use the built-in method provided by ST length() . More about features here.
Let's increase the complexity of the templates a bit to add them to our second iteration.
First we will create our playersTemplate . This is almost identical to our playerTemplate above. The only difference is that we have players from team : team.players .
String playersTemplate = "<team.players :{ player |<player.name> is <player.age><\\n>}>";
Now we will create a second template that contains the first. In this template, we can iterate over teams, and for each team we print name , the number of players length(team.players) and everything that is in playersTemplate .
String teamTemplate = "<teams:{ team |<team.name> has <length(team.players)> players<\\n>"+playersTemplate+"}>";
Now let's get it all together.
ST teamsTemplate = new ST( simpleTeamTemplate); teamsTemplate.add("teams", teams); System.out.println(teamsTemplate.render());
This will print the following for us.
Billings has 3 players Bill is 29 Steve is 30 Toby is 15 Laurel has 4 players Chad is 32 Chuck is 29 Will is 24 Ben is 26
Now you really do not want to combine your templates in this way. Adding lines together to create patterns is pretty stupid. StringTemplate offers tools to simplify this combination of partial templates. If you are interested in combining templates, you can find out more here