The problem: Put tabular text output into HTML table code
For CS00002, I hand coded the HTML to produce the program output. You can't just cut and paste into web pages because the information gets raveled into an incoherent string of words with no shape or structure. As it turns out, Glee is a pretty neat language for wrapping this output with HTML tags making it presentable. This case study illustrates how I used software sculpture to create a program producing from the raw text the HTML output I need for browser rendering. The rendered output is shown here.
TABLE OF CONTENTS:
The Cock and the Pearl | The Frog and the Ox |
The Wolf and the Lamb | Androcles |
The Dog and the Shadow | The Bat, the Birds, and the Beasts |
... | |
... | |
The Wind and the Sun | The Buffoon and the Countryman |
Hercules and the Waggoner | The Old Woman and the Wine-Jar |
The Man, the Boy, and the Donkey | The Fox and the Goat |
The solution:
Note: You can cut and paste these code fragments into the code pane of the Glee interpreter and experiment as you go along to see the actual operations live.
The Glee code:
$$ Code for reading from the
file (See CS00002):
13#asc =>nl; "TABLE"=> begin; "Aesop"=> end;
"C:\GLEE\Website\CaseStudies\AesopsFables.txt"#file[] => t;
t @->>& begin; t ->>& end => t;
t ~>(13 10 #asc) =>t;
t \~ => t; t <- => title; t <- _1 => t;
$$ Define the tag variables we need
' <tr>'=>rb; '</tr>' =>re;
' <td>'=>cb; '</td>' => ce;
'<p>'=>pb; '</p>'=>pe; '<br>'=>br;
'  '> =>sp;
$$ Define the program that does each row of raw text
'p1'#pgm{
x \43=>x;
rb nl
cb (x[1]< ~~)ce nl
cb (sp *-> 3)(x[2]< ~~) ce re
nl};
$$ Run the code
pb title pe $;
('<table>')nl
(t <-* 3#ea ' [.x]p1')
(('...' <- 50) [.x]p1)
(('...' -> 50)[.x]p1)
(t *-> 3#ea ' [.x]p1')
('</table>')$;
The Output:
<p>TABLE OF CONTENTS:</p>
<table>
<tr>
<td>The Cock and the Pearl</td>
<td>      The
Frog and the Ox</td>
</tr>
<tr>
<td>The Wolf and the Lamb</td>
<td>      Androcles</td>
</tr>
<tr>
<td>The Dog and the Shadow</td>
<td>      The
Bat, the Birds, and the Beasts</td>
</tr>
<tr>
<td>...</td>
<td>      </td>
</tr>
<tr>
<td> </td>
<td>      ...</td>
</tr>
<tr>
<td>The Wind and the Sun</td>
<td>      The
Buffoon and the Countryman</td>
</tr>
<tr>
<td>Hercules and the Waggoner</td>
<td>      The
Old Woman and the Wine-Jar</td>
</tr>
<tr>
<td>The Man, the Boy, and the Donkey</td>
<td>   The Fox and the
Goat</td>
</tr>
</table>
The play-by-play:
$$ Code for reading from the
file (See CS00002):
13#asc =>nl; "TABLE"=> begin; "Aesop"=> end;
"C:\GLEE\Website\CaseStudies\AesopsFables.txt"#file[] => t;
t @->>& begin; t ->>& end => t;
t *-> (end# -) ~>(13 10 #asc) =>t;
t \~ => t; t <- => title; t <- _1 => t;
In CS00002 I developed this code for extracting the table from the raw text
file. I then hand coded the HTML to make the output look presentable on the web
page. It's time to automate that process. I have the title line in title and the rows of the table as elements of the
sequence t after I run this code
fragment.
$$ Find start of right hand column
t[1]< $;
The Cock and the Pearl
The Frog and the
Ox
t[1]< ``&'the' $;
3 16 43 56
First, I need to find where the right hand column begins. It starts with the
word "the". "The" occurs four times and I want the third
one (index position 43 starts the second column).
$$ Confirm break between fields
t[1]< \43 %**$;
Seq[I732R1C2T:K]:
[1]String[I748R1C22:C]The Cock and the Pearl
[2]String[I754R1C19:C]The Frog and the Ox
The \Selection
operator followed by an integer breaks the string into a two item
sequence. I use %** $Verbose Display to see my progress.
$$ Define the tag variables we need
' <tr>'=>rb; '</tr>' =>re;
' <td>'=>cb; '</td>' => ce;
'<p>'=>pb; '</p>'=>pe; '<br>'=>br;
'  '> =>sp;
This is fairly self explanatory. I'm creating mnemonics for the character
strings I will use to decorate my output. Notice, for the non-blanking space
'  '> =>sp; I use the
>Enclose
operator so I can treat that string as a sequence element.
'  '> =>sp %** $;
Seq[I644R1C1T:K]:
[1]String[I619R2C6:C] 
sp *-> 3 %** $;
Seq[I693R1C3T:K]:
[1]String[I667R4C6:C] 
[2]String[I667R4C6:C] 
[3]String[I667R4C6:C] 
This illustrates my special handling of non-blanking spaces. By
"enclosing" the string, I create a one element sequence. Doing the
take 3 gives me three instances of the
string (in HTML-land that's three non-blanking spaces). I continue to carve out
my solution.
t[1]< \43 => x;
rb nl
cb (x[1]< ~~)ce nl
cb (sp *-> 3)(x[2]< ~~) ce
re nl
Yields
<tr>
<td>The Cock and the Pearl</td>
<td>      The Frog and
the Ox</td>
</tr>
I can implicitly catenate my strings together to form my compound output. Here
I carve out some code to produce the output I want for each line of input. My
source data is a sequence of two strings (the left and right columns). I index
out each string (i.e. x[1]) and < Expose each
string. I use the ~~Remove Extraneous operator (with no right argument) to
remove extraneous blanks. This is working just as I want so I need to make it
into a program to be applied to each row of the table.
$$ Define the program that
does each row of raw text
'p1'#pgm{
x \43=>x;
rb nl
cb (x[1]< ~~)ce nl
cb (sp *-> 3)(x[2]< ~~) ce re
nl};
As illustrated here, turning my carving into a working program is trivial. I
merely wrap the code in braces {...}
which turns it into a Glee block of code. I preceed this
block with the #pgm operator preceeded by
the string 'p1'naming the block. I can
display this program as follows:
p1:stringv $;
Pgm[S722R2C1:K]
Code:{
x \43=>x;
rb nl
cb (x[1]< ~~)ce nl
cb (sp *-> 3)(x[2]< ~~) ce
re nl}
Notice, I don't use the %** Verbose string operator because it would invoke
p1 before applying the operator. I would
get the verbose look at the output rather than at the block's internal makeup.
I use the :stringv $; method instead.
t[1..3]#ea'[.x]p1'
<tr>
<td>The Cock and the Pearl</td>
<td> The Frog and the Ox</td>
</tr>
<tr>
<td>The Wolf and the Lamb</td>
<td> Androcles</td>
</tr>
<tr>
<td>The Dog and the Shadow</td>
<td> The Bat, the Birds, and the
Beasts</td>
</tr>
Shows that everything is working fine in the program for a three item table.
t[1..3]#ea'[.x]p1' delivers up a subset
(first 3 elements) of t to the #ea Each operator
which takes those elements in turn. It delivers them one at a time to the left
of [.x]. When an index is a field,
a namespace is created using the left argument to build it. [.x]thus names the left argument
"x" and delivers it as the
argument to the program p1. Our program
works fine for these three elements showing it correct for beginning and ending
conditions and for an inner condition. Thus, it should work just fine for the
whole table. This gives an example of a software sculpture technique of
"reaching out and touching" the data using just enough to prove the
case.
$$ Run the code
pb title pe $;
('<table>')nl
(t<- 3#ea ' [.x]p1')
(('...' <- 50) [.x]p1)
(('...' -> 50) [.x]p1)
(t *-> 3#ea ' [.x]p1')
('</table>')$;
I now have the whole program that produces the output I want. I can cut and
paste this output into my HTML source code and I have
the table I want. There is just one other issue in this code I should explain.
Since this is an example, I don't want the whole table. I just want the first
and last three rows split by an ellipsis (...). I get this effect by using the
<-take from
front blank filland ->take from back blank filloperators on my sequence of
table items. And in the middle, I create two dummy rows. The first has an
elipsis in the left column and the second has it in the right column. I get
this effect by doing takes from the front and end on the elipsis strings. In
the first case '...'<-50 I take from
the front of a string with fills on the right. In the second case '...'->50 I take from the right on a string with
blank fills on the left. I'm using 50 for the take which must just be bigger
than the 46 (43 where the columns split plus the three character elipsis).
This completes the example. To better understand these operators and other things you can do with them, consult the operator pages according to the type of data you see being operated on.