You are encouraged to solve this task according to the task description, using any language you may know.

Create an HTML table.

And without the HTML containment

We define a generic package to output HTML tables:

The implementation of the package:

Here is the main program, using an instance of HTML_Table:

-- define the object that will the values that the table contains

-- now we instantiate the generic package HTML_Table

-- define the Item_Type and the random generator

Each time you run the program, you get different random values for the table.

Tested with Agena 2.9.5 Win32

# create an HTMLTABLE and print it to standard output #

# allowable content for the HTML table - extend the UNION and TOSTRING #

This will overwrite any file by the name of "table.html" in the current directory.

:: The command output of everything within the brackets is sent to the file "table.html", overwriting anything already in there

:: It's easier and neater to create the variables holding the random 4 digit numbers ahead of time

Uses BBC BASIC's *spool command to create a file.

To make this interesting, the table is created as a Bracmat structure and then converted to XML by a library. This has the advantage that one doesn't have to worry about HTML entities and encoding issues. The contents of the cells are generated by a function that is instantiated with a starting number when the function makeTable is called. Notice the absence of loops.

(wiki doesn't like tbody/thead tags):( of testtable.html ):

Using Hiccup (https://github.com/weavejester/hiccup):

# can build tables in the browser using DOM APIs. This approach is just

# with any templating solution built for JavaScript, and of course you

# This is one of many ways to create a table. CoffeeScript plays nice

Using Closure-HTML (https://common-lisp.net/project/closure/closure-html/) installed by the code itself via QuickLisp (http://quicklisp.org/).

X Y Z 0 -1111 111 11 1 22 -222 2222 2 4422 0 42 3 33 333 3333 4 6666 666 66

defmodule Table do

defp put_rows(n) do

Enum.map_join(1..n, fn i ->

"<tr align=right><th>#{i}</th>" <>

Enum.map_join(1..3, fn _ ->

"<td>#{:rand.uniform(2000)}</td>"

end) <> "</tr>

"

end)

end



def create_table(n\\3) do

"<table border=1>

" <>

"<th></th><th>X</th><th>Y</th><th>Z</th>

" <>

put_rows(n) <>

"</table>"

end

end



IO.puts Table.create_table

Output:

Output:

X Y Z 1 1362 1289 357 2 1161 1345 1176 3 391 62 609

Both external_format/1 and html_table/3 are used by CSV_to_HTML_translation. Keep backwards compatibility when changing or change both.



- module ( create_html_table ) .



- export ( [ external_format / 1 , html_table / 3 , task / 0 ] ) .



external_format ( XML ) -> remove_quoutes ( lists : flatten ( xmerl : export_simple_content ( [ XML ] , xmerl_xml ) ) ) .



html_table ( Table_options , Headers , Contents ) ->

Header = html_table_header ( Headers ) ,

Records = [ html_table_record ( X ) || X <- Contents ] ,

{ table , Table_options , [ Header | Records ] } .



task ( ) ->

Headers = [ " " , "X" , "Y" , "Z" ] ,

Contents = [ [ erlang : integer_to_list ( X ) , random ( ) , random ( ) , random ( ) ] || X <- lists : seq ( 1 , 3 ) ] ,

external_format ( html_table ( [ { border , 1 } , { cellpadding , 10 } ] , Headers , Contents ) ) .







html_table_header ( Items ) -> { tr , [ ] , [ { th , [ ] , [ X ] } || X <- Items ] } .



html_table_record ( Items ) -> { tr , [ ] , [ { td , [ ] , [ X ] } || X <- Items ] } .



random ( ) -> erlang : integer_to_list ( random : uniform ( 1000 ) ) .



remove_quoutes ( String ) -> lists : flatten ( string : tokens ( String , " \" " ) ) .



Output:

X Y Z 1 6 563 476 2 401 310 59 3 579 990 331

puts ( 1 , "<table>

" )

puts ( 1 , " <tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>

" )

for i = 1 to 3 do

printf ( 1 , " <tr><td>%d</td>" , i )

for j = 1 to 3 do

printf ( 1 , "<td>%d</td>" , rand ( 10000 ) )

end for

puts ( 1 , "</tr>

" )

end for

puts ( 1 , "</table>" )

Output:

open System. Xml



type XmlDocument with

member this. Add element =

this. AppendChild element

member this. Element name =

this. CreateElement ( name ) : > XmlNode

member this. Element ( name, ( attr : ( string * string ) list ) ) =

let node = this. CreateElement ( name )

for a in attr do

node. SetAttribute ( fst a, snd a )

node

member this. Element ( name, ( text : string ) ) =

let node = this. CreateElement ( name )

node. AppendChild ( this. Text text ) |> ignore

node

member this. Text text =

this. CreateTextNode ( text )

end



type XmlNode with

member this. Add element =

this. AppendChild element

end



let head = [ "" ; "X" ; "Y" ; "Z" ]



let xd = new XmlDocument ( )

let html = xd. Add ( xd. Element ( "html" ) )

html. Add ( xd. Element ( "head" ) )

. Add ( xd. Element ( "title" , "RosettaCode: Create_an_HTML_table" ) )

let table = html. Add ( xd. Element ( "body" ) ) . Add ( xd. Element ( "table" , [ ( "style" , "text-align:right" ) ] ) )

let tr1 = table. Add ( xd. Element ( "tr" ) )

for th in head do

tr1. Add ( xd. Element ( "th" , th ) ) |> ignore

for i in [ 1 ; 2 ; 3 ] do

let tr = table. Add ( xd. Element ( "tr" ) )

tr. Add ( xd. Element ( "th" , i. ToString ( ) ) ) |> ignore

for j in [ 1 ; 2 ; 3 ] do

tr. Add ( xd. Element ( "td" , ( ( i - 1 ) * 3 + j + 1000 ) . ToString ( ) ) ) |> ignore



let xw = new XmlTextWriter ( System. Console . Out )

xw. Formatting <- Formatting. Indented

xd. WriteContentTo ( xw )

Output:

(table part only)

X Y Z 1 1001 1002 1003 2 1004 1005 1006 3 1007 1008 1009

USING: html.streams literals prettyprint random xml.writer ;



: rnd ( -- n ) 10,000 random ;



{

{ "" "X" "Y" "Z" }

${ 1 rnd rnd rnd }

${ 2 rnd rnd rnd }

${ 3 rnd rnd rnd }

}

[ simple-table. ] with-html-writer pprint-xml

Output:

table style = "display: inline-table; border-collapse: collapse;" >

tr >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

X

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

Y

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

Z

/ td >

/ tr >

tr >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

1

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

9463

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

3201

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

9044

/ div >

/ td >

/ tr >

tr >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

2

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

3152

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

6685

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

928

/ div >

/ td >

/ tr >

tr >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

3

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

696

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

3803

/ div >

/ td >

td valign = "top" style = "border: 1px solid #cccccc; padding: 2px; " >

div style = "display: inline-block; " >

5079

/ div >

/ td >

/ tr >

/ table >

br / >

Printing out a group of HTML text strings is not difficult for Forth or most computer languages. Another way to do this in Forth is to extend Forth with new "words" that output the HTML tags. The HTML words will output HTML code when they are interpreted by Forth. In this example the extended Forth code looks at lot like HTML. :-) The biggest difference is that Forth requires 1 space minimum between each tag.

Although this example is not a complete HTML interpreter, with these few extensions we can demonstrate mixing HTML tags with Forth code to generate the specified random numbers in-line with HTML. We could even use Forth to compile tags together and make HTML generating sub-routines like NETREXX does.

include random.hsf



\ parser routines

: totag

[char] < PARSE pad place \ parse input up to '<' char

-1 >in +! \ move the interpreter pointer back 1 char

pad count type ;



: '"' [char] " emit ;

: '"..' '"' space ; \ output a quote char with trailing space



: toquote \ parse input to " then print as quoted text

'"' [char] " PARSE pad place

pad count type '"..' ;



: > [char] > emit space ; \ output the '>' with trailing space



\ Create some HTML extensions to the Forth interpreter

: <table> ." <table>" cr ; : </table> ." </table>" cr ;

: <table ." <table " ;

: style=" ." style=" toquote ;

: align=" ." align=" toquote ;

: border=" ." border=" toquote ;

: width=" ." width=" toquote ;

: cellspacing=" ." cellspacing=" toquote ;

: colspacing=" ." colspacing=" toquote ;



: <tr> ." <tr>" cr ; : </tr> ." </tr>" cr ;

: <td> ." <td> " totag ; : </td> ." </td>" cr ;

: <td ." <td " ;

: <thead> ." <thead>" ; : </thead> ." </thead>" ;

: <th> ." <th>" ; : </th> ." </th>" cr ;

: <th ." <th " ;

: <tbody ." <tbody " ; : </tbody> ." </tbody> " ;

: <caption> cr ." <caption>" totag ; : </caption> ." </caption>" cr ;



\ Write the source code that generates HTML in our EXTENDED FORTH

cr

<table border=" 1" width=" 30%" >

<caption> This table was created with FORTH HTML tags</caption>

<tr>

<th align=" right" > </th>

<th align=" right" > ." A" </th>

<th align=" right" > ." B" </th>

<th align=" right" > ." C" </th>

</tr>

<tr>

<th align=" right" > 1 . </th>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

</tr>

<tr>

<th align=" right" > 2 . </th>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

</tr>

<tr>

<th align=" right" > 3 . </th>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

<td align=" right" > 1000 RND . </td>

</tr>

</table>



Output:

<table border="1" width="30%" > <caption>This table was created with FORTH HTML tags</caption> <tr> <th align="right" > </th> <th align="right" > A</th> <th align="right" > B</th> <th align="right" > C</th> </tr> <tr> <th align="right" > 1 </th> <td align="right" > 338 </td> <td align="right" > 102 </td> <td align="right" > 113 </td> </tr> <tr> <th align="right" > 2 </th> <td align="right" > 430 </td> <td align="right" > 319 </td> <td align="right" > 731 </td> </tr> <tr> <th align="right" > 3 </th> <td align="right" > 333 </td> <td align="right" > 592 </td> <td align="right" > 83 </td> </tr> </table>

Result

This table was created with FORTH HTML tags A B C 1 338 102 113 2 430 319 731 3 333 592 83

Origin [ edit ]

The task could be achieved by a series of direct WRITE statements, with some simple loop to generate N lines for the table. This would not show anything beyond the usage of WRITE statements, possibly obfuscated by cunning FORMAT sequences. Instead, what follows is a trimmed version of some routines that were used for writing HTML tables of various shapes, with perhaps dozens of columns and hundreds of rows. The idea was that module HTMLSTUFF would contain an attempt at organised assistance for the task. The system would produce output tables according to the type of the output file: space-aligned or, if .csv then comma-separated, or if .html then it used the HTML table protocol. In-line code was used for the details of the body of the tables because their cells involved different types and layout (and even decoration, as with RED ... DER for negative correlations) but here the task requires only HTML and that each row show only integers so it seemed worthwhile to devise a subroutine for writing a row of integers and likewise for a row of texts. Thus, the caller need not worry over the multitude of details involved in preparing a well-formed HTML file, just invoke some subroutines with a few parameters. This is done in the mainline. The specification is for columns headed "X", "Y", and "Z" but a proper table would have more useful annotations.

These routines were written to wallow in a much larger context. For instance, each subprogram would start with a call to SUBIN naming the subprogram, and just before exit each would invoke SUBOUT. A stack of active names was thereby maintained, and was available for use by subroutine ECART (to produce trace output, annotated via the name stack with the name of the routine requesting that output), and subroutine STATE that accepted a text declaring the activity about to be started (surprisingly useful when checking and documenting the source), and if there was a disaster, subroutine CROAK reported its message and what was being attempted at each level back to the start. Similarly, (almost) all output to the screen was echoed to file TRAIL and after every 6666 lines written to the screen, there was an opportunity to stop a runaway output, and details for the I/O unit variables and associated arrays were in named COMMON via file cIOunits.for. Most of this has been commented out. There was also an attempt at dealing with annoying differences in glyphs between keyboard input, screen display, and the display rendered by text editors. This had to be extended for HTML output as certain character codes also evoked an unsuitable glyph and others interfered with the interpretation of text versus instructions. The first part of the source therefore is a wad of support routines, starting with a text I AM (see the painting by Colin McCahon) that names the programme, and another that is filled with the user's code identity. These are used in the metadata for the HTML.

Since the HTML text that results was going to be inspected by eye to catch blunders there was a lot of attention to layout, in particular the use of indenting as each level was tracked by INDEEP, and the content of a row was to appear on one (possibly long) line. Browsers often pass over hiccoughs and still present a correct-looking display, thus it is useful to employ HTML-checking routines. I have considered adding various checks to the routines in HTMLSTUFF such as that when a level was closed, its interior levels had also been closed off, but that would mean even more cogitation. Avoiding endless text shuffling was another objective, thus rather than concatenate pieces and write the result, routine HTML3 has three parts, a preamble, a body, and a tail to generate a complete line. Further, for layout assistance, if the preamble was not empty then it would be written on a new line and indented according to INDEEP, and if the tail was not empty then it would be written and the line ended. It is tempting to prepare a similar routine for presenting a single item, say HTML3TERM("<th>",TEXT(I)(1:L),"</th>") rather than preparing a compound string via "<th>"//TEXT(I)(1:L)//"</th>" first. Even more direct would be to use WRITE statements straight to the output file, employing suitable FORMAT statements, but in the larger context it was more useful to avoid this since with all output in one place via subroutine WRITE, mishaps could be attended to in one place only.

Source [ edit ]



MODULE PARAMETERS !Assorted oddities that assorted routines pick and choose from.

CHARACTER * 5 I AM !Assuage finicky compilers.

PARAMETER ( IAM = "Gnash" ) !I AM!

INTEGER LUSERCODE !One day, I'll get around to devising some string protocol.

CHARACTER * 28 USERCODE !I'm not too sure how long this can be.

DATA USERCODE,LUSERCODE / "" , 0 / !Especially before I have a text.

END MODULE PARAMETERS



MODULE ASSISTANCE

CONTAINS !Assorted routines that seem to be of general use but don't seem worth isolating..

Subroutine Croak ( Gasp ) !A dying message, when horror is suddenly encountered.

Casts out some final words and STOP, relying on the SubInOut stuff to have been used.

Cut down from the full version of April MMI, that employed the SubIN and SubOUT protocol..

Character * ( * ) Gasp !The last gasp.

COMMON KBD,MSG

WRITE ( MSG, 1 ) GASP

1 FORMAT ( "Oh dear! " ,A )

STOP "I STOP now. Farewell..." !Whatever pit I was in, I'm gone.

End Subroutine Croak !That's it.



INTEGER FUNCTION LSTNB ( TEXT ) !Sigh. Last Not Blank.

Concocted yet again by R.N.McLean (whom God preserve) December MM.

Code checking reveals that the Compaq compiler generates a copy of the string and then finds the length of that when using the latter-day intrinsic LEN_TRIM. Madness!

Can't DO WHILE (L.GT.0 .AND. TEXT(L:L).LE.' ') !Control chars. regarded as spaces.

Curse the morons who think it good that the compiler MIGHT evaluate logical expressions fully.

Crude GO TO rather than a DO-loop, because compilers use a loop counter as well as updating the index variable.

Comparison runs of GNASH showed a saving of ~3% in its mass-data reading through the avoidance of DO in LSTNB alone.

Crappy code for character comparison of varying lengths is avoided by using ICHAR which is for single characters only.

Checking the indexing of CHARACTER variables for bounds evoked astounding stupidities, such as calculating the length of TEXT(L:L) by subtracting L from L!

Comparison runs of GNASH showed a saving of ~25-30% in its mass data scanning for this, involving all its two-dozen or so single-character comparisons, not just in LSTNB.

CHARACTER * ( * ) , INTENT ( IN ) :: TEXT !The bumf. If there must be copy-in, at least there need not be copy back.

INTEGER L !The length of the bumf.

L = LEN ( TEXT ) !So, what is it?

1 IF ( L. LE .0 ) GO TO 2 !Are we there yet?

IF ( ICHAR ( TEXT ( L : L ) ) . GT . ICHAR ( " " ) ) GO TO 2 !Control chars are regarded as spaces also.

L = L - 1 !Step back one.

GO TO 1 !And try again.

2 LSTNB = L !The last non-blank, possibly zero.

RETURN !Unsafe to use LSTNB as a variable.

END FUNCTION LSTNB !Compilers can bungle it.

CHARACTER * 2 FUNCTION I2FMT ( N ) !These are all the same.

INTEGER * 4 N !But, the compiler doesn't offer generalisations.

IF ( N. LT .0 ) THEN !Negative numbers cop a sign.

IF ( N. LT . - 9 ) THEN !But there's not much room left.

I2FMT = "-!" !So this means 'overflow'.

ELSE !Otherwise, room for one negative digit.

I2FMT = "-" // CHAR ( ICHAR ( "0" ) - N ) !Thus. Presume adjacent character codes, etc.

END IF !So much for negative numbers.

ELSE IF ( N. LT .10 ) THEN !Single digit positive?

I2FMT = " " // CHAR ( ICHAR ( "0" ) + N ) !Yes. This.

ELSE IF ( N. LT .100 ) THEN !Two digit positive?

I2FMT = CHAR ( N / 10 + ICHAR ( "0" ) ) !Yes.

1 // CHAR ( MOD ( N, 10 ) + ICHAR ( "0" ) ) !These.

ELSE !Otherwise,

I2FMT = "+!" !Positive overflow.

END IF !So much for that.

END FUNCTION I2FMT !No WRITE and FORMAT unlimbering.

CHARACTER * 8 FUNCTION I8FMT ( N ) !Oh for proper strings.

INTEGER * 4 N

CHARACTER * 8 HIC

WRITE ( HIC, 1 ) N

1 FORMAT ( I8 )

I8FMT = HIC

END FUNCTION I8FMT

CHARACTER * 42 FUNCTION ERRORWORDS ( IT ) !Look for an explanation. One day, the system may offer coherent messages.

Curious collection of encountered codes. Will they differ on other systems?

Compaq's compiler was taken over by unintel; http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/fortran/lin/compiler_f/bldaps_for/common/bldaps_rterrs.htm

contains a schedule of error numbers that matched those I'd found for Compaq, and so some assumptions are added.

Copying all (hundreds!) is excessive; these seem possible for the usage so far made of error diversion.

Compaq's compiler interface ("visual" blah) has a help offering, which can provide error code information.

Compaq messages also appear in http://cens.ioc.ee/local/man/CompaqCompilers/cf/dfuum028.htm#tab_runtime_errors

Combines IOSTAT codes (file open, read etc) with STAT codes (allocate/deallocate) as their numbers are distinct.

Completeness and context remains a problem. Excess brevity means cause and effect can be confused.

INTEGER IT !The error code in question.

INTEGER LASTKNOWN !Some codes I know about.

PARAMETER ( LASTKNOWN = 26 ) !But only a few, discovered by experiment and mishap.

TYPE HINT !For them, I can supply a table.

INTEGER CODE !The code number. (But, different systems..??)

CHARACTER * 42 EXPLICATION !An explanation. Will it be the answer?

END TYPE HINT !Simple enough.

TYPE ( HINT ) ERROR ( LASTKNOWN ) !So, let's have a collection.

PARAMETER ( ERROR = ( / !With these values.

1 HINT ( - 1 , "End-of-file at the start of reading!" ) , !From examples supplied with the Compaq compiler involving IOSTAT.

2 HINT ( 0 , "No worries." ) , !Apparently the only standard value.

3 HINT ( 9 , "Permissions - read only?" ) ,

4 HINT ( 10 , "File already exists!" ) ,

5 HINT ( 17 , "Syntax error in NameList input." ) ,

6 HINT ( 18 , "Too many values for the recipient." ) ,

7 HINT ( 19 , "Invalid naming of a variable." ) ,

8 HINT ( 24 , "Surprise end-of-file during read!" ) , !From example source.

9 HINT ( 25 , "Invalid record number!" ) ,

o HINT ( 29 , "File name not found." ) ,

1 HINT ( 30 , "Unavailable - exclusive use?" ) ,

2 HINT ( 32 , "Invalid fileunit number!" ) ,

3 HINT ( 35 , "'Binary' form usage is rejected." ) , !From example source.

4 HINT ( 36 , "Record number for a non-existing record!" ) ,

5 HINT ( 37 , "No record length has been specified." ) ,

6 HINT ( 38 , "I/O error during a write!" ) ,

7 HINT ( 39 , "I/O error during a read!" ) ,

8 HINT ( 41 , "Insufficient memory available!" ) ,

9 HINT ( 43 , "Malformed file name." ) ,

o HINT ( 47 , "Attempting a write, but read-only is set." ) ,

1 HINT ( 66 , "Output overflows single record size." ) , !This one from experience.

2 HINT ( 67 , "Input demand exceeds single record size." ) , !These two are for unformatted I/O.

3 HINT ( 151 , "Can't allocate: already allocated!" ) , !These different numbers are for memory allocation failures.

4 HINT ( 153 , "Can't deallocate: not allocated!" ) ,

5 HINT ( 173 , "The fingered item was not allocated!" ) , !Such as an ordinary array that was not allocated.

6 HINT ( 179 , "Size exceeds addressable memory!" ) / ) )

INTEGER I !A stepper.

DO I = LASTKNOWN, 1 , - 1 !So, step through the known codes.

IF ( IT . EQ . ERROR ( I ) . CODE ) GO TO 1 !This one?

END DO !On to the next.

1 IF ( I. LE .0 ) THEN !Fail with I = 0.

ERRORWORDS = I8FMT ( IT ) // " is a novel code!" !Reveal the mysterious number.

ELSE !But otherwise, it is found.

ERRORWORDS = ERROR ( I ) . EXPLICATION !And these words might even apply.

END IF !But on all systems?

END FUNCTION ERRORWORDS !Hopefully, helpful.

END MODULE ASSISTANCE



MODULE LOGORRHOEA

CONTAINS

SUBROUTINE ECART ( TEXT ) !Produces trace output with many auxiliary details.

CHARACTER * ( * ) TEXT !The text to be annotated.

COMMON KBD,MSG !I/O units.

WRITE ( MSG, 1 ) TEXT !Just roll the text.

1 FORMAT ( "Trace: " ,A ) !Lacks the names of the invoking routine, and that which invoked it.

END SUBROUTINE ECART

SUBROUTINE WRITE ( OUT ,TEXT,ON ) !We get here in the end. Cast forth some pearls.

C Once upon a time, there was just confusion between ASCII and EBCDIC character codes and glyphs,

c after many variant collections caused annoyance. Now I see that modern computing has introduced

c many new variations, so that one text editor may display glyphs differing from those displayed

c by another editor and also different from those displayed when a programme writes to the screen

c in "teletype" mode, which is to say, employing the character/glyph combination of the moment.

c And in particular, decimal points and degree symbols differ and annoyance has grown.

c So, on re-arranging SAY to not send output to multiple distinations depending on the value of OUT,

c except for the special output to MSG that is echoed to TRAIL, it became less messy to make an assault

c on the text that goes to MSG, but after it was sent to TRAIL. I would have preferred to fiddle the

c "code page" for text output that determines what glyph to show for which code, but not only

c is it unclear how to do this, even if facilities were available, I suspect that the screen display

c software only loads the mysterious code page during startup.

c This fiddling means that any write to MSG should be done last, and writes of text literals

c should not include characters that will be fiddled, as text literals may be protected against change.

C Somewhere along the way, the cent character (¢) has disappeared. Perhaps it will return in "unicode".

USE ASSISTANCE !But might still have difficulty.

INTEGER OUT !The destination.

CHARACTER * ( * ) TEXT !The message. Possibly damaged. Any trailing spaces will be sent forth.

LOGICAL ON !Whether to terminate the line... TRUE sez that someone will be carrying on.

INTEGER IOSTAT !Furrytran gibberish.

c INCLUDE "cIOUnits.for" !I/O unit numbers.

COMMON KBD,MSG

c INTEGER*2,SAVE:: I Be !Self-identification.

c CALL SUBIN("Write",I Be) !Hullo!

IF ( OUT . LE .0 ) GO TO 999 !Goodbye?

c IF (IOGOOD(OUT)) THEN !Is this one in good heart?

c IF (IOCOUNT(OUT).LE.0 .AND. OUT.NE.MSG) THEN !Is it attached to a file?

c IF (IONAME(OUT).EQ."") IONAME(OUT) = "Anome" !"No name".

c 1 //I2FMT(OUT)//".txt" !Clutch at straws.

c IF (.NOT.OPEN(OUT,IONAME(OUT),"REPLACE","WRITE")) THEN !Just in time?

c IOGOOD(OUT) = .FALSE. !No! Strangle further usage.

c GO TO 999 !Can't write, so give up!

c END IF !It might be better to hit the WRITE and fail.

c END IF !We should be ready now.

c IF (OUT.EQ.MSG .AND. SCRAGTEXTOUT) CALL SCRAG(TEXT) !Output to the screen is recoded for the screen.

IF ( ON ) THEN !Now for the actual output at last. This is annoying.

WRITE ( OUT , 1 , ERR = 666 , IOSTAT = IOSTAT ) TEXT !Splurt.

1 FORMAT ( A,$ ) !Don't move on to a new line. (The "$"! Is it not obvious?)

c IOPART(OUT) = IOPART(OUT) + 1 !Thus count a part-line in case someone fusses.

ELSE !But mostly, write and advance.

WRITE ( OUT , 2 , ERR = 666 , IOSTAT = IOSTAT ) TEXT !Splurt.

2 FORMAT ( A ) !*-style "free" format chops at 80 or some such.

END IF !So much for last-moment dithering.

c IOCOUNT(OUT) = IOCOUNT(OUT) + 1 !Count another write (whole or part) so as to be not zero..

c END IF !So much for active passages.

c 999 CALL SUBOUT("Write") !I am closing.

999 RETURN !Done.

Confusions.

666 IF ( OUT . NE . MSG ) CALL CROAK ( "Can't write to unit " // I2FMT ( OUT ) !Why not?

c 1 //" (file "//IONAME(OUT)(1:LSTNB(IONAME(OUT))) !Possibly, no more disc space! In which case, this may fail also!

2 // ") message " // ERRORWORDS ( IOSTAT ) !Hopefully, helpful.

3 // " length " // I8FMT ( LEN ( TEXT ) ) // ", this: " // TEXT ) !The instigation.

STOP "Constipation!" !Just so.

END SUBROUTINE WRITE !The moving hand having writ, moves on.



SUBROUTINE SAY ( OUT ,TEXT ) !And maybe a copy to the trail file as well.

USE PARAMETERS !Odds and ends.

USE ASSISTANCE !Just a little.

INTEGER OUT !The orifice.

CHARACTER * ( * ) TEXT !The blather. Can be modified if to MSG and certain characters are found.

CHARACTER * 120 IS !For a snatched question.

INTEGER L !A finger.

c INCLUDE "cIOUnits.for" !I/O unit numbers.

COMMON KBD,MSG

c INTEGER*2,SAVE:: I Be !Self-identification.

c CALL SUBIN("Say",I Be) !Me do be Me, I say!

Chop off trailing spaces.

L = LEN ( TEXT ) !What I say may be rather brief.

1 IF ( L. GT .0 ) THEN !So, is there a last character to look at?

IF ( ICHAR ( TEXT ( L : L ) ) . LE . ICHAR ( " " ) ) THEN !Yes. Is it boring?

L = L - 1 !Yes! Trim it!

GO TO 1 !And check afresh.

END IF !A DO-loop has overhead with its iteration count as well.

END IF !Function LEN_TRIM copies the text first!!

Contemplate the disposition of TEXT(1:L)

c IF (OUT.NE.MSG) THEN !Normal stuff?

CALL WRITE ( OUT ,TEXT ( 1 : L ) , . FALSE . ) !Roll.

c ELSE !Echo what goes to MSG to the TRAIL file.

c CALL WRITE(TRAIL,TEXT(1:L),.FALSE.) !Thus.

c CALL WRITE( MSG,TEXT(1:L),.FALSE.) !Splot to the screen.

c IF (.NOT.BLABBERMOUTH) THEN !Do we know restraint?

c IF (IOCOUNT(MSG).GT.BURP) THEN !Yes. Consider it.

c WRITE (MSG,100) IOCOUNT(MSG) !Alas, triggered. So remark on quantity,

c 100 FORMAT (//I9," lines! Your spirit might flag." !Hint. (Not copied to the TRAIL file)

c 1 /," Type quit to set GIVEOVER to TRUE, with hope for "

c 2 ,"a speedy palliation,",

c 3 /," or QUIT to abandon everything, here, now",

c 4 /," or blabber to abandon further restraint,",

c 5 /," or anything else to carry on:")

c IS = REPLY("QUIT, quit, blabber or continue") !And ask.

c IF (IS.EQ."QUIT") CALL CROAK("Enough of this!") !No UPDATE, nothing.

c CALL UPCASE(IS) !Now we're past the nice distinction, simplify.

c IF (IS.EQ."QUIT") GIVEOVER = .TRUE. !Signal to those who listen.

c IF (IS.EQ."BLABBER") BLABBERMOUTH = .TRUE. !Well?

c IF (GIVEOVER) WRITE (MSG,101) !Announce hope.

c 101 FORMAT ("Let's hope that the babbler notices...") !Like, IF (GIVEOVER) GO TO ...

c IF (.NOT.GIVEOVER) WRITE (MSG,102) !Alternatively, firm resolve.

c 102 FORMAT("Onwards with renewed vigour!") !Fight the good fight.

c BURP = IOCOUNT(MSG) + ENOUGH !The next pause to come.

c END IF !So much for last-moment restraint.

c END IF !So much for restraint.

c END IF !So much for selection.

c CALL SUBOUT("Say") !I am merely the messenger.

END SUBROUTINE SAY !Enough said.

SUBROUTINE SAYON ( OUT ,TEXT ) !Roll to the screen and to the trail file as well.

C This differs by not ending the line so that further output can be appended to it.

USE ASSISTANCE

INTEGER OUT !The orifice.

CHARACTER * ( * ) TEXT !The blather.

INTEGER L !A finger.

c INCLUDE "cIOUnits.for" !I/O unit numbers.

COMMON KBD,MSG

c INTEGER*2,SAVE:: I Be !Self-identification.

c CALL SUBIN("SayOn",I Be) !Me do be another. Me, I say on!

L = LEN ( TEXT ) !How much say I on?

1 IF ( L. GT .0 ) THEN !I say on anything?

IF ( ICHAR ( TEXT ( L : L ) ) . LE . ICHAR ( " " ) ) THEN !I end it spaceish?

L = L - 1 !Yes. Trim such.

GO TO 1 !And look afresh.

END IF !So much for trailing off.

END IF !Continue with L fingering the last non-blank.

c IF (OUT.EQ.MSG) CALL WRITE(TRAIL,TEXT(1:L),.TRUE.) !Writes to the screen go also to the TRAIL.

CALL WRITE ( OUT ,TEXT ( 1 : L ) , . TRUE . ) !It is said, and more is expected.

c CALL SUBOUT("SayOn") !I am merely the messenger.

END SUBROUTINE SAYON !And further messages impend.



END MODULE LOGORRHOEA



MODULE HTMLSTUFF !Assists with the production of decorated output.

Can't say I think much of the scheme. How about <+blah> ... <-blah> rather than the assymetric <blah> ... </blah>?

Cack-handed comment format as well...

USE PARAMETERS !To ascertain who I AM.

USE ASSISTANCE !To get at LSTNB.

USE LOGORRHOEA !To get at SAYON and SAY.

INTEGER INDEEP,HOLE !I keep track of some details.

PRIVATE INDEEP,HOLE !Amongst myselves.

DATA INDEEP,HOLE / 0 , 0 / !Initially, I'm not doing anything.

Choose amongst output formats.

INTEGER LASTFILETYPENAME !Certain file types are recognised.

PARAMETER ( LASTFILETYPENAME = 2 ) !Thus, three options.

INTEGER OUTTYPE,OUTTXT,OUTCSV,OUTHTML !The recognition.

CHARACTER * 5 OUTSTYLE,FILETYPENAME ( 0 : LASTFILETYPENAME ) !Via the tail end of a file name.

PARAMETER ( FILETYPENAME = ( / ".txt" , ".CSV" , ".HTML" / ) ) !Thusly. Note that WHATFILETYPE will not recognise ".txt" directly.

PARAMETER ( OUTTXT = 0 ,OUTCSV = 1 ,OUTHTML = 2 ) !Mnemonics.

DATA OUTSTYLE / "" / !So OUTTYPE = OUTTXT. But if an output file is specified, its file type will be inspected.

TYPE HTMLMNEMONIC !I might as well get systematic, as these are global names.

CHARACTER * 9 COMMAH !This looks like a comma

CHARACTER * 9 COMMAD !And in another context, so does this.

CHARACTER * 6 SPACE !Some spaces are to be atomic.

CHARACTER * 18 RED !Decoration and

CHARACTER * 7 DER !noitaroceD.

END TYPE HTMLMNEMONIC !That's enough for now.

TYPE ( HTMLMNEMONIC ) HTMLA !I'll have one set, please.

PARAMETER ( HTMLA = HTMLMNEMONIC ( !With these values.

1 "</th><th>" , !But .html has its variants. For a heading.

2 "</td><td>" , !For a table datum.

3 " " , !A space that is not to be split.

4 '<font color="red">' , !Dabble in decoration.

5 '</font>' ) ) !Grrrr. A font is for baptismal water.

CONTAINS !Mysterious assistants.

SUBROUTINE HTML ( TEXT ) !Rolls some text, with suitable indentation.

CHARACTER * ( * ) TEXT !The text.

c INCLUDE "cIOUnits.for" !I/O unit numbers.

IF ( LEN ( TEXT ) . LE .0 ) RETURN !Possibly boring.

IF ( INDEEP. GT .0 ) THEN !Some indenting desired?

CALL WRITE ( HOLE, REPEAT ( " " ,INDEEP ) , . TRUE . ) !Yep. SAYON trims trailing spaces.

c IF (HOLE.EQ.MSG) CALL WRITE(TRAIL,REPEAT(" ",INDEEP),.TRUE.) !So I must copy.

END IF !Enough indenting.

CALL SAY ( HOLE,TEXT ) !Say the piece and end the line.

END SUBROUTINE HTML !Maintain stacks? Check entry/exit matching?



SUBROUTINE HTML3 ( HEAD,BUMF,TAIL ) !Rolls some text, with suitable indentation.

Checks the BUMF for decimal points only. HTMLALINE handles text to HTML for troublesome characters, replacing them with special names for the desired glyph.

Confusion might arise, if & is in BUMF and is not to be converted. "&" vs "&so on"; similar worries with < and >.

CHARACTER * ( * ) HEAD !If not "", the start of the line, with indentation supplied.

CHARACTER * ( * ) BUMF !The main body of the text.

CHARACTER * ( * ) TAIL !If not "", this is for the end of the line.

INTEGER LB,L1,L2 !A length and some fingers for scanning.

CHARACTER * 1 MUMBLE !These symbols may not be presented properly.

CHARACTER * 8 MUTTER !But these encodements may be interpreted as desired.

PARAMETER ( MUMBLE = "·" ) !I want certain glyphs, but encodement varies.

PARAMETER ( MUTTER = "·" ) !As does recognition.

c INCLUDE "cIOUnits.for" !I/O unit numbers.

COMMON KBD,MSG

Commence with a new line?

IF ( HEAD. NE . "" ) THEN !Is a line to be started? (Spaces are equivalent to "" as well)

IF ( INDEEP. GT .0 ) THEN !Some indentation is good.

CALL WRITE ( HOLE, REPEAT ( " " ,INDEEP ) , . TRUE . ) !Yep. SAYON trims trailing spaces.

c IF (HOLE.EQ.MSG) CALL WRITE(TRAIL, !So I must copy for the log.

c 1 REPEAT(" ",INDEEP),.TRUE.) !Hopefully, not generated a second time.

ELSE !The accountancy may be bungled.

CALL ECART ( "HTML huh? InDeep=" // I8FMT ( INDEEP ) ) !So, complain.

END IF !Also, REPEAT has misbehaved.

CALL SAYON ( HOLE,HEAD ) !Thus a suitable indentation.

END IF !So much for a starter.

Cast forth the bumf. Any trailing spaces will be dropped by SAYON.

LB = LEN ( BUMF ) !How much bumf? Trailing spaces will be rolled.

L1 = 1 !Waiting to be sent.

L2 = 0 !Syncopation.

1 L2 = L2 + 1 !Advance to the next character to be inspected..

IF ( L2. GT . LB ) GO TO 2 !Is there another?

IF ( ICHAR ( BUMF ( L2 : L2 ) ) . NE . ICHAR ( MUMBLE ) ) GO TO 1 !Yes. Advance through the untroublesome.

IF ( L1. LT . L2 ) THEN !A hit. Have any untroubled ones been passed?

CALL WRITE ( HOLE,BUMF ( L1 : L2 - 1 ) , . TRUE . ) !Yes. Send them forth.

c IF (HOLE.EQ.MSG) CALL WRITE(TRAIL,BUMF(L1:L2 - 1),.TRUE.) !With any trailing spaces included.

END IF !Now to do something in place of BUMF(L2)

L1 = L2 + 1 !Moving the marker past it, like.

CALL SAYON ( HOLE,MUTTER ) !The replacement for BUMF(L2 as was).

GO TO 1 !Continue scanning.

2 IF ( L2. GT . L1 ) THEN !Any tail end, but not ending the output line.

CALL WRITE ( HOLE,BUMF ( L1 : L2 - 1 ) , . TRUE . ) !Yes. Away it goes.

c IF (HOLE.EQ.MSG) CALL WRITE(TRAIL,BUMF(L1:L2 - 1),.TRUE.) !And logged.

END IF !So much for the bumf.

Consider ending the line.

3 IF ( TAIL. NE . "" ) CALL SAY ( HOLE,TAIL ) !Enough!

END SUBROUTINE HTML3 !Maintain stacks? Check entry/exit matching?



SUBROUTINE HTMLSTART ( OUT ,TITLE,DESC ) !Roll forth some gibberish.

INTEGER OUT !The mouthpiece, mentioned once only at the start, and remembered for future use.

CHARACTER * ( * ) TITLE !This should be brief.

CHARACTER * ( * ) DESC !This a little less brief.

CHARACTER * ( * ) METAH !Some repetition.

PARAMETER ( METAH = '<Meta Name="' ) !The syntax is dubious.

CHARACTER * 8 D !YYYYMMDD

CHARACTER * 10 T !HHMMSS.FFF

HOLE = OUT !Keep a local copy to save on parameters.

INDEEP = 0 !We start.

CALL HTML ( '<!DOCTYPE HTML PUBLIC "' !Before we begin, we wave hands.

1 // '-//W3C//DTD HTML 4.01 Transitional//EN"' !Otherwise "nowrap" is objected to, as in http://validator.w3.org/check

2 // ' "http://www.w3.org/TR/html4/loose.dtd">' ) !Endless blather.

CALL HTML ( '<HTML lang="en-NZ">' ) ! H E R E W E G O !

INDEEP = 1 !Its content.

CALL HTML ( "<Head>" ) !And the first decoration begins.

INDEEP = 2 !Its content.

CALL HTML ( "<Title>" // I AM // " " !This appears in the web page tag.

1 // TITLE ( 1 : LSTNB ( TITLE ) ) // "</Title>" ) !So it should be short.

CALL HTML ( '<Meta http-equiv="Content-Type"' !Crazed gibberish.

1 // ' content="text/html; charset=utf-8">' ) !But said to be worthy.

CALL HTML ( METAH // 'Description" Content="' // DESC // '">' ) !Hopefully, helpful.

CALL HTML ( METAH // 'Generator" Content="' // I AM // '">' ) !I said.

CALL DATE_AND_TIME ( DATE = D,TIME = T ) !Not assignments, but attachments.

CALL HTML ( METAH // 'Created" Content="' !Convert the timestamp

1 // D ( 1 : 4 ) // "-" // D ( 5 : 6 ) // "-" // D ( 7 : 8 ) !Into an international standard.

2 // " " // T ( 1 : 2 ) // ":" // T ( 3 : 4 ) // ":" // T ( 5 : 10 ) // '">' ) !For date and time.

IF ( LUSERCODE. GT .0 ) CALL HTML ( METAH !Possibly, the user's code is known.

1 // 'Author" Content="' // USERCODE ( 1 : LUSERCODE ) !If so, reveal.

2 // '"> <!-- User code as reported by GetLog.-->' ) !Disclaiming responsibility...

INDEEP = 1 !Finishing the content of the header.

CALL HTML ( "</Head>" ) !Enough of that.

CALL HTML ( "<BODY>" ) !A fresh line seems polite.

INDEEP = 2 !Its content follows..

END SUBROUTINE HTMLSTART !Others will follow on. Hopefully, correctly.

SUBROUTINE HTMLSTOP !And hopefully, this will be a good closure.

Could be more sophisticated and track the stack via INDEEP+- and names, to enable a desperate close-off if INDEEP is not 2.

IF ( INDEEP. NE .2 ) CALL ECART ( "Misclosure! InDeep not 2 but" !But,

1 // I8FMT ( INDEEP ) ) !It may not be.

INDEEP = 1 !Retreat to the first level.

CALL HTML ( "</BODY>" ) !End the "body".

INDEEP = 0 !Retreat to the start level.

CALL HTML ( "</HTML>" ) !End the whole thing.

END SUBROUTINE HTMLSTOP !Ah...



SUBROUTINE HTMLTSTART ( B,SUMMARY ) !Start a table.

INTEGER B !Border thickness.

CHARACTER * ( * ) SUMMARY !Some well-chosen words.

CALL HTML ( "<Table border=" // I2FMT ( B ) !Just so. Text digits, or, digits in text?

1 // ' summary="' // SUMMARY // '">' ) !Not displayed, but potentially used by non-display agencies...

INDEEP = INDEEP + 1 !Another level dug.

END SUBROUTINE HTMLTSTART !That part was easy.

SUBROUTINE HTMLTSTOP !And the ending is easy too.

INDEEP = INDEEP - 1 !Withdraw a level.

CALL HTML ( "</Table>" ) !Hopefully, aligning.

END SUBROUTINE HTMLTSTOP !The bounds are easy.



SUBROUTINE HTMLTHEADSTART !Start a table's heading.

CALL HTML ( "<tHead>" ) !Thus.

INDEEP = INDEEP + 1 !Dig deeper.

END SUBROUTINE HTMLTHEADSTART !Content should follow.

SUBROUTINE HTMLTHEADSTOP !And now, enough.

INDEEP = INDEEP - 1 !Retreat a level.

CALL HTML ( "</tHead>" ) !And end the head.

END SUBROUTINE HTMLTHEADSTOP !At the neck of the body?



SUBROUTINE HTMLTHEAD ( N,TEXT ) !Cast forth a whole-span table heading.

INTEGER N !The count of columns to be spanned.

CHARACTER * ( * ) TEXT !A brief description to place there.

CALL HTML3 ( "<tr><th colspan=" ,I8FMT ( N ) // ' align="center">' , "" ) !Start the specification.

CALL HTML3 ( "" ,TEXT ( 1 : LSTNB ( TEXT ) ) , "</th></tr>" ) !This text, possibly verbose.

END SUBROUTINE HTMLTHEAD !Thus, all contained on one line.



SUBROUTINE HTMLTBODYSTART !Start on the table body.

CALL HTML ( '<tBody> <!--Profuse "align" usage ' !Simple, but I'm unhappy.

1 // 'for all cells can be factored out to "row" ' !Alas, so far as I can make out.

2 // 'but not to "body"-->' ) !And I don't think much of the "comment" formalism, either.

INDEEP = INDEEP + 1 !Anyway, we're ready with the alignment.

END SUBROUTINE HTMLTBODYSTART !Others will provide the body.

SUBROUTINE HTMLTBODYSTOP !And, they've had enough.

INDEEP = INDEEP - 1 !So, up out of the hole.

CALL HTML ( "</tBody>" ) !Take a breath.

END SUBROUTINE HTMLTBODYSTOP !And wander off.

SUBROUTINE HTMLTROWTEXT ( TEXT,N ) !Roll a row of column headings.

CHARACTER * ( * ) TEXT ( : ) !The headings.

INTEGER N !Their number.

INTEGER I,L !Assistants.

CALL HTML3 ( "<tr>" , "" , "" ) !Start a row of headings-to-come, and don't end the line.

DO I = 1 ,N !Step through the headings.

L = LSTNB ( TEXT ( I ) ) !Trailing spaces are to be ignored.

IF ( L. LE .0 ) THEN !Thus discovering blank texts.

CALL HTML3 ( "" , "<th> </th>" , "" ) !This prevents the cell being collapsed.

ELSE !But for those with text,

CALL HTML3 ( "" , "<th>" // TEXT ( I ) ( 1 : L ) // "</th>" , "" ) !Roll it.

END IF !So much for that text.

END DO !On to the next.

CALL HTML3 ( "" , "" , "</tr>" ) !Finish the row, and thus the line.

END SUBROUTINE HTMLTROWTEXT !So much for texts.

SUBROUTINE HTMLTROWINTEGER ( V,N ) !Now for all integers.

INTEGER V ( : ) !The integers.

INTEGER N !Their number.

INTEGER I !A stepper.

CALL HTML3 ( '<tr align="right">' , "" , "" ) !Start a row of entries.

DO I = 1 ,N !Work through the row's values.

CALL HTML3 ( "" , "<td>" // I8FMT ( V ( I ) ) // "</td>" , "" ) !One by one.

END DO !On to the next.

CALL HTML3 ( "" , "" , "</tr>" ) !Finish the row, and thus the line.

END SUBROUTINE HTMLTROWINTEGER !All the same type is not troublesome.

END MODULE HTMLSTUFF !Enough already.



PROGRAM MAKETABLE

USE PARAMETERS

USE ASSISTANCE

USE HTMLSTUFF

INTEGER KBD,MSG

INTEGER NCOLS !The usage of V must conform to this!

PARAMETER ( NCOLS = 4 ) !Specified number of columns.

CHARACTER * 3 COLNAME ( NCOLS ) !And they have names.

PARAMETER ( COLNAME = ( / "" , "X" , "Y" , "Z" / ) ) !As specified.

INTEGER V ( NCOLS ) !A scratchpad for a line's worth.

COMMON KBD,MSG !I/O units.

KBD = 5 !Keyboard.

MSG = 6 !Screen.

CALL GETLOG ( USERCODE ) !Who has poked me into life?

LUSERCODE = LSTNB ( USERCODE ) !Ah, text gnashing.



CALL HTMLSTART ( MSG, "Powers" , "Table of integer powers" ) !Output to the screen will do.

CALL HTMLTSTART ( 1 , "Successive powers of successive integers" ) !Start the table.

CALL HTMLTHEADSTART !The table heading.

CALL HTMLTHEAD ( NCOLS, "Successive powers" ) !A full-width heading.

CALL HTMLTROWTEXT ( COLNAME,NCOLS ) !Headings for each column.

CALL HTMLTHEADSTOP !So much for the heading.

CALL HTMLTBODYSTART !Now for the content.

DO I = 1 , 10 !This should be enough.

V ( 1 ) = I !The unheaded row number.

V ( 2 ) = I ** 2 !Its square.

V ( 3 ) = I ** 3 !Cube.

V ( 4 ) = I ** 4 !Fourth power.

CALL HTMLTROWINTEGER ( V,NCOLS ) !Show a row's worth..

END DO !On to the next line.

CALL HTMLTBODYSTOP !No more content.

CALL HTMLTSTOP !End the table.

CALL HTMLSTOP

END



Output [ edit ]

As yet another demonstration of the vagaries of text interpretation, notice that the blank column heading, carefully converted to nbsp; (no leading ampersand here!) does not appear when the page is displayed, despite the "pre-formatted" hint.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML lang="en-NZ"> <Head> <Title>Gnash Powers</Title> <Meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <Meta Name="Description" Content="Table of integer powers"> <Meta Name="Generator" Content="Gnash"> <Meta Name="Created" Content="2016-02-09 01:07:48.359"> <Meta Name="Author" Content="Nicky"> <!-- User code as reported by GetLog.--> </Head> <BODY> <Table border= 1 summary="Successive powers of successive integers"> <tHead> <tr><th colspan= 4 align="center">Successive powers</th></tr> <tr><th> </th><th>X</th><th>Y</th><th>Z</th></tr> </tHead> <tBody> <!--Profuse "align" usage for all cells can be factored out to "row" but not to "body"--> <tr align="right"><td> 1</td><td> 1</td><td> 1</td><td> 1</td></tr> <tr align="right"><td> 2</td><td> 4</td><td> 8</td><td> 16</td></tr> <tr align="right"><td> 3</td><td> 9</td><td> 27</td><td> 81</td></tr> <tr align="right"><td> 4</td><td> 16</td><td> 64</td><td> 256</td></tr> <tr align="right"><td> 5</td><td> 25</td><td> 125</td><td> 625</td></tr> <tr align="right"><td> 6</td><td> 36</td><td> 216</td><td> 1296</td></tr> <tr align="right"><td> 7</td><td> 49</td><td> 343</td><td> 2401</td></tr> <tr align="right"><td> 8</td><td> 64</td><td> 512</td><td> 4096</td></tr> <tr align="right"><td> 9</td><td> 81</td><td> 729</td><td> 6561</td></tr> <tr align="right"><td> 10</td><td> 100</td><td> 1000</td><td> 10000</td></tr> </tBody> </Table> </BODY> </HTML>

And without the HTML containment [ edit ]

<tHead> Successive powers X Y Z </tHead> <tBody> 1 1 1 1 2 4 8 16 3 9 27 81 4 16 64 256 5 25 125 625 6 36 216 1296 7 49 343 2401 8 64 512 4096 9 81 729 6561 10 100 1000 10000 </tBody>

html/template is a package in the standard library.

package main



import (

"fmt"

"html/template"

"os"

)



type row struct {

X , Y , Z int

}



var tmpl = `<table>

<tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>

{{range $ix, $row := .}} <tr><td>{{$ix}}</td>

<td>{{$row.X}}</td>

<td>{{$row.Y}}</td>

<td>{{$row.Z}}</td></tr>

{{end}}</table>

`



func main () {

// create template

ct := template . Must ( template . New ( "" ) . Parse ( tmpl ))



// make up data

data := make ([] row , 4 )

for r := range data {

data [ r ] = row { r * 3 , r * 3 + 1 , r * 3 + 2 }

}



// apply template to data

if err := ct . Execute ( os . Stdout , data ); err != nil {

fmt . Println ( err )

}

}

Output:

import groovy.xml.MarkupBuilder



def createTable ( columns, rowCount ) {

def writer = new StringWriter ( )

new MarkupBuilder ( writer ) . table ( style: 'border:1px solid;text-align:center;' ) {

tr {

th ( )

columns. each { title -> th ( title ) }

}

( 1 .. rowCount ) . each { row ->

tr {

td ( row )

columns. each { td ( ( Math . random ( ) * 9999 ) as int ) }

}

}

}

writer. toString ( )

}



println createTable ( [ 'X' , 'Y' , 'Z' ] , 3 )

Output:

X Y Z 1 6106 9898 1584 2 1641 9387 3858 3 8970 4843 681

import Data . List ( unfoldr )

import Control . Monad ( forM _ )



import qualified Text . Blaze . Html5 as B

import Text . Blaze . Html . Renderer . Pretty ( renderHtml )



import System . Random ( RandomGen , getStdGen , randomRs , split )



makeTable

:: RandomGen g

=> [ String ] -> Int -> g -> B . Html

makeTable headings nRows gen =

B . table $

do B . thead $ B . tr $ forM _ ( B . toHtml <$> headings ) B . th

B . tbody $

forM _

( zip [ 1 .. nRows ] $ unfoldr ( Just . split ) gen )

( \ ( x , g ) ->

B . tr $

forM _

( take ( length headings ) ( x : randomRs ( 1000 , 9999 ) g ) )

( B . td . B . toHtml ) )



main :: IO ( )

main = do

g <- getStdGen

putStrLn $ renderHtml $ makeTable [ "" , "X" , "Y" , "Z" ] 3 g

Or using the Shakespeare templates from the Yesod web framework.

{-# LANGUAGE QuasiQuotes #-}



import Data . List ( elemIndex )

import Text . Hamlet ( shamlet , Html )

import Text . Cassius ( Css , renderCss , cassius )

import Text . Blaze . Html . Renderer . String ( renderHtml )

import System . Random ( getStdGen , randomRs )



styles :: p -> Css

styles = [ cassius |

table , th , td

border: 1px solid black

border - collapse: collapse

th , td

padding: 15px

th , . rowLabel

background - color: # 895

td

text - align: right

| ]



renderTable :: [ [ Int ] ] -> Html

renderTable xs = [ shamlet |

$ doctype 5

< html >

< head >

< style >

# { renderCss $ styles undefined }

< body >

< table >

< tr >

< th >

$ forall header <- headers

< th > # { header }

$ forall row <- xs

< tr >

$ maybe index <- elemIndex row xs

< td . rowLabel > # { index + 1 }

$ nothing

< td >?

$ forall cell <- row

< td > # { cell }

| ]

where

headers = [ 'X' , 'Y' , 'Z' ]



main :: IO ( )

main = renderHtml . renderTable . rowsOf 3 . take 9 <$> randomValues >>= putStrLn

where

rowsOf _ [ ] = [ ]

rowsOf n xs = take n xs : rowsOf n ( drop n xs )

randomValues = randomRs ( 1 , 9999 ) <$> getStdGen

procedure main ( )

printf ( "<table>

<tr><th></th><th>X</th><th>Y</th><th>Z</th>" )

every r := 1 to 4 do {

printf ( "</tr>

<tr><td>%d</td>" , r )

every 1 to 3 do printf ( "<td>%d</td>" ,? 9999 ) # random 4 digit numbers per cell

}

printf ( "</tr>

</table>

" )

end



link printf

printf.icn provides printf

Output:

We can define:

ele=: 4 : 0

nm=. x -.LF

lf=. x -.nm

; ( '<' ,nm, '>' ) ,L: 0 y ,L: 0 '</' ,nm, '>' ,lf

)



hTbl=: 4 : 0

rows=. 'td' <@ele" 1 ":&.> y

'table' ele ( 'tr' ,LF ) <@ele ( 'th' ele x ) ; rows

)

With these definitions:

( '' ;;: 'X Y Z' ) hTbl ":&.> ( i. 5 ) ,.i. 5 3

<table><tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>

<tr><td> 0 </td><td> 0 </td><td> 1 </td><td> 2 </td></tr>

<tr><td> 1 </td><td> 3 </td><td> 4 </td><td> 5 </td></tr>

<tr><td> 2 </td><td> 6 </td><td> 7 </td><td> 8 </td></tr>

<tr><td> 3 </td><td> 9 </td><td> 10 </td><td> 11 </td></tr>

<tr><td> 4 </td><td> 12 </td><td> 13 </td><td> 14 </td></tr>

</table>

Or, if running under jhs:

jhtml ( '' ;;: 'X Y Z' ) hTbl ":&.> ( i. 5 ) ,.i. 5 3

to display the table inline, as html.

Works with: Java version 1.5+

This example assumes the header row is the first row in the given array and does not add row numbers. They will need to be added by the programmer when constructing the array.

public class HTML {



public static String array2HTML ( Object [ ] [ ] array ) {

StringBuilder html = new StringBuilder (

"<table>" ) ;

for ( Object elem:array [ 0 ] ) {

html. append ( "<th>" + elem. toString ( ) + "</th>" ) ;

}

for ( int i = 1 ; i < array. length ; i++ ) {

Object [ ] row = array [ i ] ;

html. append ( "<tr>" ) ;

for ( Object elem:row ) {

html. append ( "<td>" + elem. toString ( ) + "</td>" ) ;

}

html. append ( "</tr>" ) ;

}

html. append ( "</table>" ) ;

return html. toString ( ) ;

}



public static void main ( String [ ] args ) {

Object [ ] [ ] ints = { { "" , "X" , "Y" , "Z" } , { 1 , 1 , 2 , 3 } , { 2 , 4 , 5 , 6 } , { 3 , 7 , 8 , 9 } , { 4 , 10 , 11 , 12 } } ;

System . out . println ( array2HTML ( ints ) ) ;

}

}

Output:

Iterative [ edit ]

< html >< head >< title > Table maker </ title >< script type = "application/javascript" >



// normally, don't do this: at least name it something other than "a"

Node. prototype . a = function ( e ) { this . appendChild ( e ) ; return this }



function ce ( tag , txt ) {

var x = document. createElement ( tag ) ;

x. textContent = ( txt === undefined ) ? '' : txt ;

return x ;

}



function make_table ( cols , rows ) {

var tbl = ce ( 'table' , '' ) , tr = ce ( 'tr' ) , th ;



tbl. a ( tr. a ( ce ( 'th' ) ) ) ;



var z = 'Z' . charCodeAt ( 0 ) ;

for ( var l = z - cols + 1 ; l <= z ; l ++ )

tr. a ( ce ( 'th' , String . fromCharCode ( l ) ) ) ;



for ( var r = 1 ; r <= rows ; r ++ ) {

tbl. a ( tr = ce ( 'tr' ) . a ( ce ( 'th' , r ) ) ) ;

for ( var c = 0 ; c < cols ; c ++ )

tr. a ( ce ( 'td' , Math . floor ( Math . random ( ) * 10000 ) ) ) ;

}



document. body

. a ( ce ( 'style' ,

'td, th {border: 1px solid #696;' +

'padding:.4ex} td {text-align: right }' +

'table { border-collapse: collapse}' ) )

. a ( tbl ) ;

}

</ script ></ head >

< body >< script > make_table ( 5 , 4 ) </ script ></ body ></ html >

Functional [ edit ]

Alternatively we could:

Separate the data definition from the HTML generation, and fold a more general HTML rendering function over a data tree.

( ( ) => {

'use strict' ;



// HTML ---------------------------------------------



// treeHTML :: tree

// {tag :: String, text :: String, kvs :: Dict}

// -> String

const treeHTML = tree =>

foldTree (

( x , xs ) => ` < $ { x. tag + attribString ( x. kvs ) } > ` + (

'text' in x ? (

x. text

) : '

'

) + concat ( xs ) + ` </ $ { x. tag } >

` ) (

tree

) ;



// attribString :: Dict -> String

const attribString = dct =>

dct ? (

' ' + Object . keys ( dct )

. reduce (

( a , k ) => a + k + '="' + dct [ k ] + '" ' , ''

) . trim ( )

) : '' ;



// TEST ---------------------------------------------

const main = ( ) => {

const

tableStyle = {

style : "width:25%; border:2px solid silver;"

} ,

trStyle = {

style : "border:1px solid silver;text-align:right;"

} ,

strCaption = 'Table generated by JS' ;



const

n = 3 ,

colNames = take ( n ) ( enumFrom ( 'A' ) ) ,

dataRows = map (

x => Tuple ( x ) ( map ( randomRInt ( 100 ) ( 9999 ) ) (

colNames

) ) ) ( take ( n ) ( enumFrom ( 1 ) ) ) ;



const

// TABLE AS TREE STRUCTURE -----------------

tableTree = Node ( {

tag : 'table' ,

kvs : tableStyle

} ,

append ( [

Node ( {

tag : 'caption' ,

text : 'Table source generated by JS'

} ) ,

// HEADER ROW -----------------------

Node ( {

tag : 'tr' ,

} ,

map ( k => Node ( {

tag : 'th' ,

kvs : {

style : "text-align:right;"

} ,

text : k

} ) ) ( cons ( '' ) ( colNames ) )

)

// DATA ROWS ------------------------

] ) ( map ( tpl => Node ( {

tag : 'tr' ,

kvs : trStyle

} , cons (

Node ( {

tag : 'th' ,

text : fst ( tpl )

} ) ) (

map ( v => Node ( {

tag : 'td' ,

text : v. toString ( )

} ) ) ( snd ( tpl ) )

) ) ) ( dataRows ) )

) ;



// Return a value and/or apply console.log to it.

// (JS embeddings vary in their IO channels)

const strHTML = treeHTML ( tableTree ) ;

return (

console. log ( strHTML )

//strHTML

) ;

} ;





// GENERIC FUNCTIONS --------------------------------



// Node :: a -> [Tree a] -> Tree a

const Node = ( v , xs ) => ( {

type : 'Node' ,

root : v ,

nest : xs || [ ]

} ) ;



// Tuple (,) :: a -> b -> (a, b)

const Tuple = a => b => ( {

type : 'Tuple' ,

'0' : a ,

'1' : b ,

length : 2

} ) ;



// append (++) :: [a] -> [a] -> [a]

// append (++) :: String -> String -> String

const append = xs => ys => xs. concat ( ys ) ;



// chr :: Int -> Char

const chr = String . fromCodePoint ;



// concat :: [[a]] -> [a]

// concat :: [String] -> String

const concat = xs =>

0 < xs. length ? ( ( ) => {

const unit = 'string' !== typeof xs [ 0 ] ? (

[ ]

) : '' ;

return unit. concat . apply ( unit , xs ) ;

} ) ( ) : [ ] ;



// cons :: a -> [a] -> [a]

const cons = x => xs => [ x ] . concat ( xs ) ;



// enumFrom :: a -> [a]

function * enumFrom ( x ) {

let v = x ;

while ( true ) {

yield v ;

v = succ ( v ) ;

}

}



// enumFromToChar :: Char -> Char -> [Char]

const enumFromToChar = m => n => {

const [ intM , intN ] = [ m , n ] . map (

x => x. charCodeAt ( 0 )

) ;

return Array . from ( {

length : Math . floor ( intN - intM ) + 1

} , ( _ , i ) => String . fromCodePoint ( intM + i ) ) ;

} ;



// foldTree :: (a -> [b] -> b) -> Tree a -> b

const foldTree = f => tree => {

const go = node =>

f ( node. root , node. nest . map ( go ) ) ;

return go ( tree ) ;

} ;



// fst :: (a, b) -> a

const fst = tpl => tpl [ 0 ] ;



// isChar :: a -> Bool

const isChar = x =>

( 'string' === typeof x ) && ( 1 === x. length ) ;



// map :: (a -> b) -> [a] -> [b]

const map = f => xs =>

( Array . isArray ( xs ) ? (

xs

) : xs. split ( '' ) ) . map ( f ) ;



// ord :: Char -> Int

const ord = c => c. codePointAt ( 0 ) ;



// randomRInt :: Int -> Int -> () -> Int

const randomRInt = low => high => ( ) =>

low + Math . floor (

( Math . random ( ) * ( ( high - low ) + 1 ) )

) ;



// snd :: (a, b) -> b

const snd = tpl => tpl [ 1 ] ;



// succ :: Enum a => a -> a

const succ = x =>

isChar ( x ) ? (

chr ( 1 + ord ( x ) )

) : isNaN ( x ) ? (

undefined

) : 1 + x ;



// take :: Int -> [a] -> [a]

// take :: Int -> String -> String

const take = n => xs =>

'GeneratorFunction' !== xs. constructor . constructor . name ? (

xs. slice ( 0 , n )

) : [ ] . concat . apply ( [ ] , Array . from ( {

length : n

} , ( ) => {

const x = xs. next ( ) ;

return x. done ? [ ] : [ x. value ] ;

} ) ) ;



// MAIN ---

return main ( ) ;

} ) ( ) ;

Output:

Table source generated by JS A B C 1 8464 1650 8275 2 547 9794 8690 3 3702 1170 9004



Raw HTML output:

<table style="width:25%; border:2px solid silver;"> <caption>Table source generated by JS</caption> <tr> <th style="text-align:right;"></th> <th style="text-align:right;">A</th> <th style="text-align:right;">B</th> <th style="text-align:right;">C</th> </tr> <tr style="border:1px solid silver;text-align:right;"> <th>1</th> <td>8464</td> <td>1650</td> <td>8275</td> </tr> <tr style="border:1px solid silver;text-align:right;"> <th>2</th> <td>547</td> <td>9794</td> <td>8690</td> </tr> <tr style="border:1px solid silver;text-align:right;"> <th>3</th> <td>3702</td> <td>1170</td> <td>9004</td> </tr> </table>

Works with: jq version 1.4

def html_row:

"<tr>",

" \(.[] | "<td>\(.)</td>")",

"</tr>";



def html_header:

"<thead align = 'right'>",

" \(html_row)",

"</thead>";



def html_table(header):

"<table>",

" \(header | html_header)",

" <tbody align = 'right'>",

" \(.[] | html_row)",

" </tbody",

"</table>";



# Prepend the sequence number

def html_table_with_sequence(header):

length as $length

| . as $in

| [range(0;length) | [.+1] + $in[.]] | html_table(header);

Example

def data:

[ [4,5,6],

[41, 51, 61],

[401, 501, 601] ];



# The first column has no header

data | html_table_with_sequence( ["", "X", "Y", "Z"] )

Output:

$ jq -r -n -f Create_an_HTML_table.jq

<table>

<thead align = 'right'>

<tr>

<td></td>

<td>X</td>

<td>Y</td>

<td>Z</td>

</tr>

</thead>

<tbody align = 'right'>

<tr>

<td>1</td>

<td>4</td>

<td>5</td>

<td>6</td>

</tr>

<tr>

<td>2</td>

<td>41</td>

<td>51</td>

<td>61</td>

</tr>

<tr>

<td>3</td>

<td>401</td>

<td>501</td>

<td>601</td>

</tr>

</tbody

</table>

function tag(x::Pair, attr::Pair...)

t, b = x

attrstr = join(" $n=\"$p\"" for (n, p) in attr)

return "<$t$attrstr>$b</$t>"

end



colnames = split(",X,Y,Z", ',')



header = join(tag(:th => txt) for txt in colnames) * "

"

rows = collect(tag(:tr => join(tag(:td => i, :style => "font-weight: bold;") * join(tag(:td => rand(1000:9999)) for j in 1:3))) for i in 1:6)

body = "

" * join(rows, '

') * "

"

table = tag(:table => string('

', header, body, '

'), :style => "width: 60%")

println(table)

Output:

X Y Z 1 5399 5770 3362 2 4564 1577 5428 3 6257 7290 6138 4 3912 5163 2451 5 1426 1874 3944 6 3896 9827 7006



The raw html:

// version 1.1.3



import java. util . Random



fun main ( args : Array < String > ) {

val r = Random ( )

val sb = StringBuilder ( )

val i = " " // indent

with ( sb ) {

append ( "<html>

<head>

" )

append ( "<style>

" )

append ( "table, th, td { border: 1px solid black; }

" )

append ( "th, td { text-align: right; }

" )

append ( "</style>

</head>

<body>

" )

append ( "<table style= \" width:60% \" >

" )

append ( "$i<thead>

" )

append ( "$i$i<tr><th></th>" )

for ( c in 'X' .. 'Z' ) append ( "<th>$c</th>" )

append ( "</tr>

" )

append ( "$i</thead>

" )

append ( "$i<tbody>

" )

val f = "$i$i<tr><td>%d</td><td>%d</td><td>%d</td><td>%d</td></tr>

"

for ( j in 1 .. 4 ) {

append ( f. format ( j, r. nextInt ( 10000 ) , r. nextInt ( 10000 ) , r. nextInt ( 10000 ) ) )

}

append ( "$i</tbody>

" )

append ( "</table>

" )

append ( "</body>

</html>" )

}

println ( sb. toString ( ) )

}

Output:

Sample output:

Lambdatalk outputs standard HTML/CSS code sent to the web browser who does the job.



{ table

{ @ style = "background:#ffe; width:50%;" }

{ tr { @ style = "text-align:right; font:bold 1.0em arial;" }

{ td } { td X } { td Y } { td Z } }

{ map { lambda { :i }

{ tr { td { b :i } }

{ map { lambda { _ }

{ td { @ style = "text-align:right; font:italic 1.0em courier;" }

{ floor { * { random } 10000 } } } }

{ serie 1 3 } } } }

{ serie 1 3 } } }



Output:

X Y Z 1 4220 7476 4414 2 6 5335 1381 3 8549 1598 5380

define rand4dig => integer_random(9999, 1)



local(

output = '<table border=2 cellpadding=5 cellspace=0>

<tr>'

)



with el in (' ,X,Y,Z') -> split(',') do {

#output -> append('<th>' + #el + '</th>')

}

#output -> append('</tr>

')



loop(5) => {

#output -> append('<tr>

<td style="font-weight: bold;">' + loop_count + '</td>')

loop(3) => {

#output -> append('<td>' + rand4dig + '</td>')

}

#output -> append('</tr>

')

}

#output -> append('</table>

')



#output

Output:

X Y Z 1 5991 9892 6754 2 8441 3816 322 3 8976 4175 202 4 6705 8225 8069 5 7558 496 2577

<table border=2 cellpadding=5 cellspace=0> <tr><th> </th><th>X</th><th>Y</th><th>Z</th></tr> <tr> <td style="font-weight: bold;">1</td><td>5991</td><td>9892</td><td>6754</td></tr> <tr> <td style="font-weight: bold;">2</td><td>8441</td><td>3816</td><td>322</td></tr> <tr> <td style="font-weight: bold;">3</td><td>8976</td><td>4175</td><td>202</td></tr> <tr> <td style="font-weight: bold;">4</td><td>6705</td><td>8225</td><td>8069</td></tr> <tr> <td style="font-weight: bold;">5</td><td>7558</td><td>496</td><td>2577</td></tr> </table>

This creates and saves an html file, then calls web browser to display it.

A time delay is needed to allow this, then the file is deleted.



nomainwin



quote$ = chr$ ( 34 )



html$ = "<html><head></head><body>"



html$ = html$ + "<table border =" + quote$ + "6" + quote$ + " solid rules =none ; cellspacing =" + quote$ + "10" + quote$ + "> <th> </th> <th> X </th> <th> Y </th> <th> Z </th>"



for i = 1 to 4

d1$ = str$ ( i )

d2$ = str$ ( int ( 10000 * rnd ( 1 ) ) )

d3$ = str$ ( int ( 10000 * rnd ( 1 ) ) )

d4$ = str$ ( int ( 10000 * rnd ( 1 ) ) )

html$ = html$ + "<tr align =" ; quote$; "right" ; quote$; "> <th>" ; d1$; " </th> <td>" + d2$ + " </td> <td>" + d3$ + " </td> <td>" + d4$ + " </td> </tr>"

next i



html$ = html$ + "</table>"



html$ = html$ + "</body></html>"



open "table.html" for output as # o

# o html$;

close # o



address$ = "table.html"

run "explorer.exe " ; address$



timer 5000 , [ on ]

wait

[ on ]

timer 0



kill "table.html"



wait



sub quit w$

close # w$

end

end sub



on htmlTable (data)

str = "<table>"



-- table head

put "<thead><tr><th> </th>" after str

repeat with cell in data[1]

put "<th>"&cell&"</th>" after str

end repeat

put "</tr></thead>" after str



-- table body

put "<tbody>" after str

cnt = data.count

repeat with i = 2 to cnt

put "<tr><td>"&(i-1)&"</td>" after str

repeat with cell in data[i]

put "<td>"&cell&"</td>" after str

end repeat

put "</tr>" after str

end repeat

put "</tbody>" after str



put "</table>" after str

return str

end

tableData = [\

["X", "Y", "Z"],\

["1", "2", "3"],\

["4", "5", "6"],\

["7", "8", "9"]\

]



htmlCode = htmlTable(tableData)



-- render the result in a text member (which only supports simple/ancient HTML)

m = new(#text)

m.text = "<html><body>"&htmlCode&"</body></html>"

This function is written so as to take arbitrary table data. Its argument is a (Lua) table of (Lua) tables, where each sub-table is one row of the HTML table. The first row is assumed to be the column headings.

function htmlTable ( data )

local html = "<table>

<tr>

<th></th>

"

for _ , heading in pairs ( data [ 1 ] ) do

html = html .. "<th>" .. heading .. "</th>" .. "

"

end

html = html .. "</tr>

"

for row = 2 , # data do

html = html .. "<tr>

<th>" .. row - 1 .. "</th>

"

for _ , field in pairs ( data [ row ] ) do

html = html .. "<td>" .. field .. "</td>

"

end

html = html .. "</tr>

"

end

return html .. "</table>"

end



local tableData = {

{ "X" , "Y" , "Z" } ,

{ "1" , "2" , "3" } ,

{ "4" , "5" , "6" } ,

{ "7" , "8" , "9" }

}



print ( htmlTable ( tableData ) )

Output:

<table> <tr> <th></th> <th>X</th> <th>Y</th> <th>Z</th> </tr> <tr> <th>1</th> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <th>2</th> <td>4</td> <td>5</td> <td>6</td> </tr> <tr> <th>3</th> <td>7</td> <td>8</td> <td>9</td> </tr> </table>



MODULE HtmlTable {

tag$ = LAMBDA$ ( a$ ) -> {

= LAMBDA$ a$ -> {

IF ISNUM THEN w$ = STR$ ( NUMBER , 0 ) ELSE w$ = LETTER$

READ ? part$

= "<" + a$ + IF $ ( LEN ( part$ ) > 0 -> " " + part$ , "" ) + ">" + w$ + "</" + a$ + ">" + CHR$ ( 13 ) + CHR$ ( 10 )

}

}

INVENTORY Fun

STACK NEW {

DATA "html" , "head" , "body" , "table" , "tr" , "th" , "td"

WHILE NOT EMPTY

OVER ' duplicate top of stack

APPEND Fun , LETTER$: = tag$ ( LETTER$ )

END WHILE

}

DEF body0$ = "" , body$ = ""

STACK NEW {

DATA "" , "X" , "Y" , "Z"

FOR i = 1 TO 4

body0$ += Fun$ ( "th" ) ( LETTER$ )

z$ = ""

FOR j = 1 TO 3 : z$ += Fun$ ( "td" ) ( RANDOM ( 0 , 9999 ) , { align = "right" } ) : NEXT j

body$ += Fun$ ( "tr" ) ( Fun$ ( "th" ) ( i ) + z$ )

NEXT i

}

table$ = fun$ ( "table" ) ( fun$ ( "tr" ) ( body0$ ) + body$ , "border=1 cellpadding=10 cellspacing=0" )

DOCUMENT final$ = "<!DOCTYPE html>" + CHR$ ( 13 ) + CHR$ ( 10 )

final$ = fun$ ( "html" ) ( fun$ ( "head" ) ( "" ) + fun$ ( "body" ) ( table$ ) , { lang = "en" } )

file$ = "c:\doc.html"

REPORT final$

CLIPBOARD final$

SAVE.DOC final$ , file$

WIN file$ ' execute, no wait

}

HtmlTable



Output:

<!DOCTYPE html> <html lang="en"><head></head> <body><table border=1 cellpadding=10 cellspacing=0><tr><th></th> <th>X</th> <th>Y</th> <th>Z</th> </tr> <tr><th>1</th> <td align="right">9007</td> <td align="right">1425</td> <td align="right">4897</td> </tr> <tr><th>2</th> <td align="right">1795</td> <td align="right">6858</td> <td align="right">9682</td> </tr> <tr><th>3</th> <td align="right">2233</td> <td align="right">8270</td> <td align="right">5221</td> </tr> <tr><th>4</th> <td align="right">6619</td> <td align="right">3688</td> <td align="right">4052</td> </tr> </table> </body> </html>

x := RandomInteger[10];

Print["<table>", "

","<tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>"]

Scan[Print["<tr><td>", #, "</td><td>", x, "</td><td>", x, "</td><td>","</td></tr>"] & , Range[3]]

Print["</table>"]

Output:

<table> <tr><th></th><th>X</th><th>Y</th><th>Z</th></tr> <tr><td>1</td><td>6</td><td>10</td><td></td></tr> <tr><td>2</td><td>1</td><td>10</td><td></td></tr> <tr><td>3</td><td>6</td><td>7</td><td></td></tr> </table>

function htmltable ( fid,table,Label )

fprintf ( fid, '<table>

<thead align = "right">

' ) ;

if nargin< 3 ,

fprintf ( fid, ' <tr><th></th><td>X</td><td>Y</td><td>Z</td></tr>

</thead>

<tbody align = "right">

' ) ;

else

fprintf ( fid, ' <tr><th></th>' ) ;

fprintf ( fid, '<td>%s</td>' ,Label { : } ) ;

fprintf ( fid, '</tr>

</thead>

<tbody align = "right">

' ) ;

end ;

fprintf ( fid, ' <tr><td>%2i</td><td>%5i</td><td>%5i</td><td>%5i</td></tr>

' , [ 1 : size ( table, 1 ) ;table' ] ) ;

fprintf ( fid, ' </tbody>

</table>

' ) ;

end

Output:

>> htmltable(1,ceil(rand(5,3)*10000)) <table> <thead align = "right"> <tr><th></th><td>X</td><td>Y</td><td>Z</td></tr> </thead> <tbody align = "right"> <tr><td> 1</td><td> 6639</td><td> 1110</td><td> 296</td></tr> <tr><td> 2</td><td> 4864</td><td> 1252</td><td> 8412</td></tr> <tr><td> 3</td><td> 3800</td><td> 4556</td><td> 3752</td></tr> <tr><td> 4</td><td> 5728</td><td> 6897</td><td> 2157</td></tr> <tr><td> 5</td><td> 2272</td><td> 8503</td><td> 7021</td></tr> </tbody> </table>

MODULE testCGI;



FROM InOut IMPORT WriteCard , WriteLn , WriteString , WriteBf;

FROM Arguments IMPORT ArgTable , GetEnv;

FROM Strings IMPORT Assign , Length , String;



VAR EnvVars : ArgTable;



PROCEDURE ReadEnvVar;



VAR Value : String;

i : CARDINAL ;



BEGIN

WriteString ( '<table border="1" cellpadding="4" width="80%" align="center">' ) ;

WriteString ( '<tr><th>Index</th><th>Length</th><th>Content</th></tr>' ) ;

i := 0 ;

LOOP

IF EnvVars^ [ i ] = NIL THEN EXIT END ;

Assign ( Value , EnvVars^ [ i ] ^ ) ;

WriteString ( '<tr><td align="center">' ) ;

WriteCard ( i , 2 ) ;

WriteString ( '</td><td align="center">' ) ;

WriteCard ( Length ( Value ) , 3 ) ;

WriteString ( '</td><td>' ) ; WriteString ( Value ) ;

WriteString ( "</td></tr>" ) ;

WriteLn;

INC ( i )

END ;

WriteString ( "</table>" ) ;

END ReadEnvVar;



BEGIN

GetEnv ( EnvVars ) ;

WriteString ( 'Content-type:text/html' ) ;

WriteLn;

WriteLn;

WriteString ( '<html><head>' ) ;

WriteString ( '<title>CGI with the Mocka Modula-2 compiler</title>' ) ;

WriteString ( '</head><body>' ) ;

WriteLn;

WriteString ( '<center><h2>CGI environment passed along by your browser</h2></center><p>' ) ;

ReadEnvVar;

WriteString ( '</body></html>' ) ;

WriteLn;

WriteBf

END testCGI.

Translation of: Ursa

This program outputs the HTML table to the console.

import Nanoquery.Util



random = new(Random)



println "<table>"



// generate header

println "<tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>"



// generate five rows

for i in range(1, 5)

println "<tr><td style=\"font-weight: bold;\">" + i + "</td>"

println "<td>" + int($random.getInt(8999) + 1000) + "</td>"

println "<td>" + int($random.getInt(8999) + 1000) + "</td>"

println "<td>" + int($random.getInt(8999) + 1000) + "</td>"

println "</tr>"

end for



println "</table>"

/* NetRexx */

options replace format comments java crossref symbols nobinary



-- create some test data. Put the data in a Rexx indexed string

maxI = 1000

rng = Random ( )

xyz = ''

xyz [ 0 ] = 1 ; xyz [ 1 ] = '. X Y Z' -- use a dot to indicate an empty cell

loop r_ = 1 for 5

ra = r_ rng. nextInt ( maxI ) rng. nextInt ( maxI ) rng. nextInt ( maxI )

xyz [ 0 ] = r_ + 1 ; xyz [ r_ + 1 ] = ra

end r_



-- build an HTML string

html = htmlHeader ( )

html = html || htmlTable ( xyz )

html = html || htmlFooter ( )



-- display HTML at standard output device

say html



return



-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- HTML boilerplate header

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

method htmlHeader ( ) public static returns Rexx

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

' -

|| '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

' -

|| '<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">

' -

|| '<head>

' -

|| '<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>

' -

|| '<title>RCreateHTMLTable</title>

' -

|| '<style type="text/css">

' -

|| '<!--

' -

|| '/* <![DATA[ */

' -

|| 'body {font-family: "Lucida Grande", "Geneva", "Verdana", "Helvetica Neue", "Helvetica", "DejaVu Sans", "Arial", sans-serif;}

' -

|| 'table, th, td {table-layout: fixed; border: 1px solid black; border-collapse: collapse; padding: 0.25em; font-size: 85%;}

' -

|| 'th, td {width: 6em;}

' -

|| 'th {color: white; background-color: green;}

' -

|| 'td {text-align: right;}

' -

|| 'p.classname {

' -

|| ' font-size: inherit;

' -

|| '}

' -

|| '/* ]] */

' -

|| '//-->

' -

|| '</style>

' -

|| '</head>

' -

|| '<body>

' -

|| '<h1>Rosetta Code – NetRexx Sample Output</h2>

' -

|| '<h2><a href="http://rosettacode.org/wiki/Create_an_HTML_table">Create an HTML table</a></h2>

' -

|| ''



return html



-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- HTML footer

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

method htmlFooter ( ) public static returns Rexx

html = '</body>

' -

|| '</html>

' -

|| ''

return html



-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- Create the table

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

method htmlTable ( rows, caption = '' ) public static returns Rexx

html = '<table>

'

if caption. length ( ) > 0 then do

html = html -

|| '<caption>' caption '</caption>

' -

|| '<thead>

' -

|| ''

end

html = html -

|| htmlCsvTableRow ( rows [ 1 ] , 'th' ) '

' -

|| '</thead>

' -

|| '<tbody>

' -

|| ''

loop r_ = 2 to rows [ 0 ]

html = html -

|| htmlCsvTableRow ( rows [ r_ ] )

end r_

html = html -

|| '</tbody>

' -

|| '</table>

' -

|| ''

return html



-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- Add a row to the table

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

method htmlCsvTableRow ( row, tag = 'td' , sep = ' ' , emptyCell = '.' ) public static returns Rexx

if tag = null then tag = 'td'

row = row. strip ( 't' )

-- replace HTML special characters with symbol entities

row = row. changestr ( '&' , '&' ) -- need to do this one first to avoid double translation

row = row. changestr ( '"' , '"' )

row = row. changestr ( "'" , ''' )

row = row. changestr ( '<' , '<' )

row = row. changestr ( '>' , '>' )

elmts = ''

elmts [ 0 ] = 0

e_ = 0

loop while row. length ( ) > 0

parse row elmt ( sep ) row

if elmt == emptyCell then elmt = ' ' -- replace empy cells with non-breaking spaces

e_ = e_ + 1 ; elmts [ 0 ] = e_; elmts [ e_ ] = elmt

end

html = '<tr>

' -

|| ''

loop e_ = 1 to elmts [ 0 ]

html = html -

|| '<' tag '>' elmts [ e_ ] '</' tag '>

' -

|| ''

end e_

html = html -

|| '</tr>

' -

|| ''

return html





Output:

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

= "http://www.w3.org/1999/xhtml" lang = "en-US" xml: lang = "en-US" > html xmlnsxml:

head >

meta http-equiv = "Content-type" content = "text/html;charset=UTF-8" / >

title > / title >

style type = "text/css" >

<!--

/* <![DATA[ */

body {font-family: "Lucida Grande", "Geneva", "Verdana", "Helvetica Neue", "Helvetica", "DejaVu Sans", "Arial", sans-serif;}

table, th, td {table-layout: fixed; border: 1px solid black; border-collapse: collapse; padding: 0.25em; font-size: 85%;}

th, td {width: 6em;}

th {color: white; background-color: green;}

td {text-align: right;}

p.classname {

font-size: inherit;

}

/* ]] */

//-->

/ style >

/ head >

body >

h1 > – NetRexx Sample Output / h2 >

href = "http://rosettacode.org/wiki/Create_an_HTML_table" > h2 >< a / >< / h2 > a >

table >

tr >

th > / th >

th > / th >

th > / th >

th > / th >

/ tr >



/ thead >

tbody >

tr >

td > / td >

td > / td >

td > / td >

td > / td >

/ tr >

tr >

td > / td >

td > / td >

td > / td >

td > / td >

/ tr >

tr >

td > / td >

td > / td >

td > / td >

td > / td >

/ tr >

tr >

td > / td >

td > / td >

td > / td >

td > / td >

/ tr >

tr >

td > / td >

td > / td >

td > / td >

td > / td >

/ tr >

/ tbody >

/ table >

/ body >

/ html >



Output:

; file: html-table.lsp

; url: http://rosettacode.org/wiki/Create_an_HTML_table

; author: oofoe 2012-01-29



( seed ( time-of-day ) ) ; Initialize random number generator.



; The "tab" variable tracks the HTML indent. "pad" composes a line

; with the appropriate indent and a terminal newline.



( setq tab 0 )

( define ( pad text ) ( string ( dup " " tab ) text "

" ) )



; NewLISP allows almost any character in an identifier, so I can name

; my functions after the HTML elements they invoke. This one formats a

; single table data cell.



( define ( < td > text ) ( pad ( string "<td>" text "</td>" ) ) )



; "<tr>" will accept either a number of arguments, each one to be

; formatted as a table cell, or a single list argument, which is

; broken into table cells. For convenience, I format each list item

; with the "<td>" function so I can feed it raw lists.



( define ( < tr > )

( let ( ( data ( args ) )

( s ( pad "<tr>" ) ) )



( if ( list? ( data 0 ) ) ( setq data ( data 0 ) ) )



( inc tab )

( dolist ( el data ) ( extend s ( < td > el ) ) )

( dec tab )



( extend s ( pad "</tr>" ) )

s ) )



; By defining "<table>" as a macro, I ensure that the rows won't be

; evaluated until I've got the table started, which preserves the

; formatting.



( define-macro ( < table > )

( let ( ( s ( pad "<table>" ) ) )

( inc tab ) ( doargs ( row ) ( extend s ( eval row ) ) ) ( dec tab )

( extend s ( pad "</table>" ) )

s

) )



; Test



( print ( < table > ( < tr > "" "X" "Y" "Z" )

( < tr > ( cons 0 ( rand 1000 3 ) ) )

( < tr > ( cons 1 ( rand 1000 3 ) ) )

( < tr > ( cons 2 ( rand 1000 3 ) ) )

) )



( exit )

Output:

<table> <tr> <td></td> <td>X</td> <td>Y</td> <td>Z</td> </tr> <tr> <td>0</td> <td>289</td> <td>824</td> <td>462</td> </tr> <tr> <td>1</td> <td>49</td> <td>600</td> <td>84</td> </tr> <tr> <td>2</td> <td>511</td> <td>219</td> <td>742</td> </tr> </table>

Table:

X Y Z 0 289 824 462 1 49 600 84 2 511 219 742

import math, htmlgen

randomize()



template randTD(): expr = td($random(1000..9999))

proc randTR(x): auto =

tr(td($x, style="font-weight: bold"), randTD, randTD, randTD)



echo table(

tr(th"", th"X", th"Y", th"Z"),

randTR 1,

randTR 2,

randTR 3,

randTR 4,

randTR 5)

Output:

X Y Z 1 5084 7059 8308 2 6185 3549 8831 3 8063 5561 1675 4 2777 1769 6570 5 5465 9508 4775

Raw output:

<table><tr><th></th><th>X</th><th>Y</th><th>Z</th></tr><tr><td style="font-weight: bold">1</td><td>5084</td><td>7059</td><td>8308</td></tr><tr><td style="font-weight: bold">2</td><td>6185</td><td>3549</td><td>8831</td></tr><tr><td style="font-weight: bold">3</td><td>8063</td><td>5561</td><td>1675</td></tr><tr><td style="font-weight: bold">4</td><td>2777</td><td>1769</td><td>6570</td></tr><tr><td style="font-weight: bold">5</td><td>5465</td><td>9508</td><td>4775</td></tr></table>



﻿ class CreateTable {

function : Main ( args : String [ ] ) ~ Nil {

s := String -> New ( ) ;



s -> Append ( "<table>" ) ;

s -> Append ( "<thead align = \" right \" >" ) ;

s -> Append ( "<tr><th></th>" ) ;

td := "XYZ" ;

for ( i := 0 ; i < 3 ; i += 1 ; ) {

s -> Append ( "<td>" ) ;

s -> Append ( td -> Get ( i ) ) ;

s -> Append ( "</td>" ) ;

} ;

s -> Append ( "</tr>" ) ;

s -> Append ( "</thead>" ) ;

s -> Append ( "<tbody align = \" right \" >" ) ;

for ( i := 0 ; i < 3 ; i += 1 ; ) {

s -> Append ( "<tr><td>" ) ;

s -> Append ( i ) ;

s -> Append ( "</td>" ) ;

for ( j := 0 ; j < 3 ; j += 1 ; ) {

s -> Append ( "<td>" ) ;

s -> Append ( ( Float -> Random ( ) * 10000 ) -> As ( Int ) ) ;

s -> Append ( "</td>" ) ;

} ;

s -> Append ( "</tr>" ) ;

} ;

s -> Append ( "</tbody>" ) ;

s -> Append ( "</table>" ) ;



s -> PrintLine ( ) ;

}

}



A simple printf method:

let ( ) =

let buf = Buffer . create 1 in

let s = Buffer . add_string buf in

Random . self_init ( ) ;

s "<table>" ;

s "<thead align='right'>" ;

s "<tr><th></th>" ;

List . iter ( fun v ->

s ( "<td>" ^ v ^ "</td>" )

) [ "X" ; "Y" ; "Z" ] ;

s "</tr>" ;

s "</thead>" ;

s "<tbody align='right'>" ;

for i = 0 to pred 3 do

s ( "<tr><td>" ^ string_of_int i ^ "</td>" ) ;

for j = 0 to pred 3 do

s ( "<td>" ^ string_of_int ( Random . int 1000 ) ^ "</td>" ) ;

done ;

s "</tr>" ;

done ;

s "</tbody>" ;

s "</table>" ;

print_endline ( Buffer . contents buf )

With a dedicated library [ edit ]

Using the library ocaml-xhtml. With this library the validity of the pages is guaranteed by the OCaml type system.

open XHTML . M_01_01



let _td s = td [ pcdata s ]

let _th s = th [ pcdata s ]



let my_table =

table ~a : [ a_border 1 ]

( tr

( _th "" ) [

( _th "X" ) ;

( _th "Y" ) ;

( _th "Z" ) ]

)

[

( tr

( _td "1" ) [

( _td "aa" ) ;

( _td "bb" ) ;

( _td "cc" ) ]

) ;

( tr

( _td "2" ) [

( _td "dd" ) ;

( _td "ee" ) ;

( _td "ff" ) ]

) ;

]



let my_page =

html

( head ( title ( pcdata "My Page" ) ) [ ] )

( body

[ h1 [ pcdata "My Table" ] ;

my_table ;

]

)



let ( ) =

pretty_print ~width : 80 print_string my_page

TyXml [ edit ]

The library TyXml contains a module for XHTML that provides the same interface than the previous ocaml-xhtml library.

# use "topfind"

# require "tyxml"



module X = Xhtml . M_01_01 (* XHTML 1.1 *)

module P = Xhtml . P_01_01



let make_table ( ) =

let td1 = X . td [ X . pcdata "1" ] in

let td2 = X . td [ X . pcdata "2" ] in

let td3 = X . td [ X . pcdata "3" ] in

let my_tr = X . tr td1 [ td2 ; td3 ] in

let my_table = X . table my_tr [ ] in

( my_table )



let ( ) =

let my_title = X . title ( X . pcdata "My Page" ) in

let my_head = X . head my_title [ ] in

let my_h1 = X . h1 [ X . pcdata "My Table" ] in



let my_table = make_table ( ) in



let my_body = X . body [ my_h1 ; my_table ] in

let my_html = X . html my_head my_body in

P . print print_endline my_html ;

;;

The previous function make_table () produces a simple table, we can replace it by the function below to output a more complex table with thead and tbody :

let make_table ( ) =

let br = X . a_border 1 in

let th s = X . th [ X . pcdata s ] in

let td s = X . td [ X . pcdata s ] in

let my_thead = X . thead ( X . tr ( th "" ) [ th "X" ; th "Y" ; th "Z" ] ) [ ] in

let my_tr1 = X . tr ( td "1" ) [ td "AAA" ; td "BBB" ; td "CCC" ] in

let my_tr2 = X . tr ( td "2" ) [ td "DDD" ; td "EEE" ; td "FFF" ] in

let my_tr3 = X . tr ( td "3" ) [ td "GGG" ; td "HHH" ; td "III" ] in

let my_tbody = X . tbody my_tr1 [ my_tr2 ; my_tr3 ] in

let my_table = X . tablex ~thead : my_thead ~a : [ br ] my_tbody [ ] in

( my_table )

As a complete web application, using the "Roads" web programming library. Connect your browser to http://localhost:8080/table after starting the program.

declare



[ Roads ] = { Module . link [ 'x-ozlib://wmeyer/roads/Roads.ozf' ] }



fun { Table Session }

html (

head ( title ( "Show a table with row and column headings" )

style ( type: "text/css"

css ( td 'text-align' :center )

) )

body (

{ TagFromList table

tr ( th th ( "X" ) th ( "Y" ) th ( "Z" ) )

|

{ CreateRows 3 5 }

} ) )

end



fun { CreateRows NumCols NumRows }

{ List . map { List . number 1 NumRows 1 }

fun { $ Row }

{ TagFromList tr

td ( { Int . toString Row } )

|

{ List . map { List . number 1 NumCols 1 }

fun { $ Col }

SequentialNumber = ( Row - 1 ) * NumCols + Col

in

td ( { Int . toString SequentialNumber } )

end

} }

end

}

end



TagFromList = List . toTuple



in



{ Roads . registerFunction table Table }

{ Roads . run }

html ( n = 3 ) = {

print ( "<table>

<tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>" ) ;

for ( i = 1 , n ,

print1 ( "<tr><td>" i "</td>" ) ;

for ( j = 1 , 3 , print1 ( "<td>" random ( 9999 ) "</td>" ) ) ;

print ( "</tr>" )

) ;

print ( "</table>" )

} ;

Output:

<table> <tr><th></th><th>X</th><th>Y</th><th>Z</th></tr> <tr><td>1</td><td>6055</td><td>6794</td><td>6034</td></tr> <tr><td>2</td><td>8930</td><td>1992</td><td>7087</td></tr> <tr><td>3</td><td>9592</td><td>5836</td><td>7980</td></tr> </table>

Note also the built-in printtex command, which allows the analogous task to be written as

printtex ( matrix ( 4 , 4 , i , j , if ( i == 1 , if ( j == 1 , "" , Strchr ( 86 + j ) ) , if ( j == 1 , i , random ( 9999 ) ) ) ) )

See Delphi

Opcodes of interest: SDC -- simple document; R!I -- ranged random integer

<@ SDCLIT>

<@ DTBLIT>

<@ DTRLITLIT>

<@ DTDLITLIT>|[style]background-color:white</@>

<@ DTD>X</@>

<@ DTD>Y</@>

<@ DTD>Z</@>|[style]width:100%; background-color:brown;color:white; text-align:center</@>

<@ ITEFORLIT>10|

<@ DTRLITCAP>

<@ DTDPOSFORLIT>...|[style]background-color:Brown; color:white; text-align:right</@>

<@ DTDCAPLIT><@ SAYR!ILI2>1|9999</@>|[style]width:50;text-align:right</@>

<@ DTDCAPLIT><@ SAYR!ILI2>1|9999</@>|[style]width:50;text-align:right</@>

<@ DTDCAPLIT><@ SAYR!ILI2>1|9999</@>|[style]width:50;text-align:right</@>

|[style]background-color:white;color:black</@>

</@>

</@>

|Number Table</@>

my @heading = qw ( X Y Z ) ;

my $rows = 5 ;

print '<table><thead><td>' ,

( map { "<th>$_</th>" } @heading ) ,

"</thead><tbody>" ;



for ( 1 .. $rows ) {

print "<tr><th>$_</th>" ,

( map { "<td>" . int ( rand ( 10000 ) ) . "</td>" } @heading ) ,

"</tr>" ;

}



print "</tbody></table>" ;

Note that this is a rather inane way (because of the inane task specification) of generating structured document. For serious work, one should use a module such as XML or HTML for well-formedness instead of this ad hoc method.

plain text approach [ edit ]

puts(1,"<table border=2>

")

puts(1," <tr><th></th>")

for j=1 to 3 do

printf(1,"<th>%s</th>",'W'+j)

end for

puts(1,"</tr>

")

for i=1 to 3 do

printf(1," <tr><td>%d</td>",i)

for j=1 to 3 do

printf(1,"<td>%d</td>",rand(10000))

end for

puts(1,"</tr>

")

end for

puts(1,"</table>")

Output:

X Y Z 1 3287 6480 6510 2 8500 1908 5352 3 3287 6600 3953



The raw HTML

more structured [ edit ]

include xml.e

sequence contents = {}

for r=0 to 3 do

sequence rowcontent = {}

string thtd = iff(r=0?"th":"td")

for c=0 to 3 do

string content = iff(r=0?"XYZ"[max(1,c)..c]:

sprintf("%d",iff(c=0?r:rand(9999))))

sequence col = xml_new_element(thtd,content)

col = xml_set_attribute(col,"style","text-align:right; padding: 5px;")

rowcontent = append(rowcontent,col)

end for

sequence row = xml_new_element("tr",rowcontent)

contents = append(contents,row)

end for

sequence table = xml_new_element("table",contents)

table = xml_set_attribute(table, "border", "2")

sequence doc = xml_new_doc(table,"")

puts(1,xml_sprint(doc))

Output:

X Y Z 1 7923 3194 3339 2 7782 6177 8690 3 1474 7271 8167



The raw XML

table border = "2" >

tr >

th style = "text-align:right; padding: 5px;" / >

th style = "text-align:right; padding: 5px;" > / th >

th style = "text-align:right; padding: 5px;" > / th >

th style = "text-align:right; padding: 5px;" > / th >

/ tr >

tr >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

/ tr >

tr >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

/ tr >

tr >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

td style = "text-align:right; padding: 5px;" > / td >

/ tr >

/ table >

normal style [ edit ]

<?php

/**

* @author Elad Yosifon

* @desc HTML Table - normal style

*/

$cols = array ( '' , 'X' , 'Y' , 'Z' ) ;

$rows = 3 ;



$html = '<html><body><table><colgroup>' ;

foreach ( $cols as $col )

{

$html .= '<col style="text-align: left;" />' ;

}

unset ( $col ) ;

$html .= '</colgroup><thead><tr>' ;



foreach ( $cols as $col )

{

$html .= "<td> {$col} </td>" ;

}

unset ( $col ) ;



$html .= '</tr></thead><tbody>' ;

for ( $r = 1 ; $r <= $rows ; $r ++ )

{

$html .= '<tr>' ;

foreach ( $cols as $key => $col )

{

$html .= '<td>' . ( ( $key > 0 ) ? rand ( 1 , 9999 ) : $r ) . '</td>' ;

}

unset ( $col ) ;

$html .= '</tr>' ;

}

$html .= '</tbody></table></body></html>' ;



echo $html ;



template engine style [ edit ]

<?php

/**

* @author Elad Yosifon

* @desc HTML Table - template engine style

*/

$cols = array ( '' , 'X' , 'Y' , 'Z' ) ;

$rows = 3 ;

?>

<html>

<body>

<table>

<colgroup>

<?php foreach ( $cols as $col ) : ?>

<col style="text-align: left;" />

<?php endforeach ; unset ( $col ) ?>

</colgroup>

<thead>

<tr>

<?php foreach ( $cols as $col ) : ?>

<td> <?php echo $col ?> </td>

<?php endforeach ; unset ( $col ) ?>

</tr>

</thead>

<tbody>

<?php for ( $r = 1 ; $r <= $rows ; $r ++ ) : ?>

<tr>

<?php foreach ( $cols as $key => $col ) : ?>

<td> <?php echo ( $key > 0 ) ? rand ( 1 , 9999 ) : $r ?> </td>

<?php endforeach ; unset ( $col ) ?>

</tr>

<?php endfor ; ?>

</tbody>

</table>

</body>

</html>



(load "@lib/xhtml.l")



(<table> NIL NIL '(NIL (NIL "X") (NIL "Y") (NIL "Z"))

(for N 3

(<row> NIL N 124 456 789) ) )



/* Create an HTML table. 6/2011 */



create: procedure options (main);





create_table: procedure (headings, table_contents);



declare headings(*) character (10) varying;

declare table_contents(*, *) fixed;

declare (i, row, col) fixed;



put skip edit ('<table>') (a);

/* Headings. */

put skip edit ('<tr><th></th> ') (a);

/* For an empty column heading */

do i = 1 to hbound(headings);

put edit ('<th>', headings(i), '</th> ' ) (a);

end;

put edit ('</tr>') (a);



/* Table contents. */



do row = 1 to hbound(table_contents, 1);

/* row number */

put skip edit ('<tr><td>', row, '</td> ') (a);

/* row contents */

do col = 1 to hbound(table_contents, 2);

put edit ('<td>', table_contents(row, col), '</td> ' ) (a);

end;

put edit ('</tr>') (a);

end;

put skip edit ('</table>' ) (a);

end create_table;



declare headings (3) character (1) static initial ('X', 'Y', 'Z');



declare table_contents(3, 3) fixed static initial (

4, -3, 8,

7, 2, -6,

11, 1, 15);



call create_table (headings, table_contents);



end create;



# Converts Microsoft .NET Framework objects into HTML that can be displayed in a Web browser.

ConvertTo-Html -inputobject ( Get-Date )



# Create a PowerShell object using a HashTable

$object = [ PSCustomObject ] @ {

'A' = ( Get - Random -Minimum 0 -Maximum 10 ) ;

'B' = ( Get - Random -Minimum 0 -Maximum 10 ) ;

'C' = ( Get - Random -Minimum 0 -Maximum 10 ) }



$object | ConvertTo-Html



Output:



<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >

< html xmlns = "http://www.w3.org/1999/xhtml" >

< head >

< title > HTML TABLE </ title >

</ head >< body >

< table >

< colgroup >< col />< col />< col />< col />< col />< col />< col />< col />< col />< col />< col />< col />< col />< col />< col /></ colgroup >

< tr >< th > DisplayHint </ th >< th > DateTime </ th >< th > Date </ th >< th > Day </ th >< th > DayOfWeek </ th >< th > DayOfYear </ th >< th > Hour </ th >< th > Kind </ th >< th > Milliseco

nd </ th >< th > Minute </ th >< th > Month </ th >< th > Second </ th >< th > Ticks </ th >< th > TimeOfDay </ th >< th > Year </ th ></ tr >

< tr >< td > DateTime </ td >< td > Sunday , October 26 , 2014 2 : 32 : 31 PM </ td >< td > 10 / 26 / 2014 12 :00:00 AM </ td >< td > 26 </ td >< td > Sunday </ td >< td > 299 </ td >< td > 14 <

/ td >< td > Local </ td >< td > 563 </ td >< td > 32 </ td >< td > 10 </ td >< td > 31 </ td >< td > 635499307515634638 </ td >< td > 14 : 32 : 31.5634638 </ td >< td > 2014 </ td ></ tr >

</ table >

</ body ></ html >



<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >

< html xmlns = "http://www.w3.org/1999/xhtml" >

< head >

< title > HTML TABLE </ title >

</ head >< body >

< table >

< colgroup >< col />< col />< col /></ colgroup >

< tr >< th > C </ th >< th > B </ th >< th > A </ th ></ tr >

< tr >< td > 8 </ td >< td > 7 </ td >< td > 3 </ td ></ tr >

</ table >

</ body ></ html >



When raw results are exported to Out-File cmdlet like this:



$object | ConvertTo-Html | Out -File -FilePath $env :temp\test.html ; invoke-item $env :temp\test.html



Output:

A B C 5 8 1



:- use_module ( library ( http / html_write ) ) .



theader ( [ ] ) -- > [ ] . theader ( [ H | T ] ) -- > html ( th ( H ) ) , theader ( T ) .

trows ( [ ] , _ ) -- > [ ] . trows ( [ R | T ] , N ) -- > html ( tr ( [ td ( N ) , \trow ( R ) ] ) ) , { N1 is N + 1 } , trows ( T , N1 ) .

trow ( [ ] ) -- > [ ] . trow ( [ E | T ] ) -- > html ( td ( E ) ) , trow ( T ) .



table :-

Header = [ 'X' , 'Y' , 'Z' ] ,

Rows = [

[ 7055 , 5334 , 5795 ] ,

[ 2895 , 3019 , 7747 ] ,

[ 140 , 7607 , 8144 ] ,

[ 7090 , 475 , 4140 ]

] ,

phrase ( html ( table ( [ tr ( \theader ( Header ) ) , \trows ( Rows , 1 ) ] ) ) , Out , [ ] ) ,

print_html ( Out ) .

Create an HTML table







Title.s = "Create an HTML table"



head.s = ""

head.s + "<html><head><title>" + Title.s + "</title></head><body>" + chr ( 13 ) + chr ( 10 )



tablehead.s

tablehead.s + "<table border=1 cellpadding=10 cellspacing=0>" + chr ( 13 ) + chr ( 10 )

tablehead.s + "<tr><th></th><th>X</th><th>Y</th><th>Z</th></tr>" + chr ( 13 ) + chr ( 10 )



index = 0



tablebody.s = ""

for row = 1 to 4

index + 1

tablebody.s + "<tr><th>" + str ( index ) + "</th>"

for col = 1 to 3

tablebody.s + "<td align=" + chr ( 34 ) + "right" + chr ( 34 ) + ">" + str ( Random ( 9999 , 1 ) ) + "</td>"

next

tablebody.s + "</tr>" + chr ( 13 ) + chr ( 10 )

next



tablefoot.s = ""

tablefoot.s + "</table>" + chr ( 13 ) + chr ( 10 )



foot.s = ""

foot.s + "</body></html>" + chr ( 13 ) + chr ( 10 )



FileName.s = "Create_an_HTML_table.html"

If CreateFile ( 0 ,FileName.s )

WriteString ( 0 ,head.s )

WriteString ( 0 ,tablehead.s )

WriteString ( 0 ,tablebody.s )

WriteString ( 0 ,tablefoot.s )

WriteString ( 0 ,foot.s )

CloseFile ( 0 )

Else

Debug "Not WriteString :" + FileName.s

EndIf



; RunProgram(FileName.s)



Output:

X Y Z 1 6638 5838 5360 2 2995 3856 3093 3 37 7644 812 4 4428 1100 3721



The raw HTML



import random



def rand9999 ( ) :

return random . randint ( 1000 , 9999 )



def tag ( attr = '' , **kwargs ) :

for tag , txt in kwargs. items ( ) :

return '<{tag}{attr}>{txt}</{tag}>' . format ( ** locals ( ) )



if __name__ == '__main__' :

header = tag ( tr = '' . join ( tag ( th = txt ) for txt in ',X,Y,Z' . split ( ',' ) ) ) + '

'

rows = '

' . join ( tag ( tr = '' . join ( tag ( ' style="font-weight: bold;"' , td = i )

+ '' . join ( tag ( td = rand9999 ( ) )

for j in range ( 3 ) ) ) )

for i in range ( 1 , 6 ) )

table = tag ( table = '

' + header + rows + '

' )

print ( table )

Output:

X Y Z 1 6040 4697 7055 2 2525 5468 6901 3 8851 3727 8379 4 5313 4396 1765 5 4013 5924 6082

The raw HTML



Or, folding a general HTML render function over a tree of data:

Translation of: JavaScript

Works with: Python version 3.6

from functools import ( reduce )

import itertools

import random





# HTML RENDERING ----------------------------------------



# treeHTML :: tree

# {tag :: String, text :: String, kvs :: Dict}

# -> HTML String

def treeHTML ( tree ) :

return foldTree (

lambda x: lambda xs: (

f "<{x['tag'] + attribString(x)}>" + (

str ( x [ 'text' ] ) if 'text' in x else '

'

) + '' . join ( xs ) + f "</{x['tag']}>

"

)

) ( tree )





# attribString :: Dict -> String

def attribString ( dct ) :

kvs = dct [ 'kvs' ] if 'kvs' in dct else None

return ' ' + reduce (

lambda a , k: a + k + '="' + kvs [ k ] + '" ' ,

kvs. keys ( ) , ''

) . strip ( ) if kvs else ''





# HTML TABLE FROM GENERATED DATA ------------------------





def main ( ) :

# Number of columns and rows to generate.

n = 3



# Table details -------------------------------------

strCaption = 'Table generated with Python'

colNames = take ( n ) ( enumFrom ( 'A' ) )

dataRows = map (

lambda x: ( x , map (

lambda _: random . randint ( 100 , 9999 ) ,

colNames

) ) , take ( n ) ( enumFrom ( 1 ) ) )

tableStyle = {

'style' : "width:25%; border:2px solid silver;"

}

trStyle = {

'style' : "border:1px solid silver;text-align:right;"

}



# TREE STRUCTURE OF TABLE ---------------------------

tableTree = Node ( { 'tag' : 'table' , 'kvs' : tableStyle } ) ( [

Node ( {

'tag' : 'caption' ,

'text' : strCaption

} ) ( [ ] ) ,



# HEADER ROW --------------------------------

( Node ( { 'tag' : 'tr' } ) (

Node ( {

'tag' : 'th' ,

'kvs' : { 'style' : 'text-align:right;' } ,

'text' : k

} ) ( [ ] ) for k in ( [ '' ] + colNames )

) )

] +

# DATA ROWS ---------------------------------

list ( Node ( { 'tag' : 'tr' , 'kvs' : trStyle } ) (

[ Node ( { 'tag' : 'th' , 'text' : tpl [ 0 ] } ) ( [ ] ) ] +

list ( Node (

{ 'tag' : 'td' , 'text' : str ( v ) } ) ( [ ] ) for v in tpl [ 1 ]

)

) for tpl in dataRows )

)



print (

treeHTML ( tableTree )

# dataRows

)





# GENERIC -----------------------------------------------



# Node :: a -> [Tree a] -> Tree a

def Node ( v ) :

return lambda xs: { 'type' : 'Node' , 'root' : v , 'nest' : xs }





# enumFrom :: Enum a => a -> [a]

def enumFrom ( x ) :

return itertools . count ( x ) if type ( x ) is int else (

map ( chr , itertools . count ( ord ( x ) ) )

)





# foldTree :: (a -> [b] -> b) -> Tree a -> b

def foldTree ( f ) :

def go ( node ) :

return f ( node [ 'root' ] ) (

list ( map ( go , node [ 'nest' ] ) )

)

return lambda tree: go ( tree )





# take :: Int -> [a] -> [a]

# take :: Int -> String -> String

def take ( n ) :

return lambda xs: (

xs [ 0 :n ]

if isinstance ( xs , list )

else list ( itertools . islice ( xs , n ) )

)





if __name__ == '__main__' :

main ( )

Output:

Table generated with Python A B C 1 7469 7407 6448 2 4135 3299 6586 3 8264 6951 8882



Raw HTML output

table style = "width:25%; border:2px solid silver;" >

caption > / caption >

tr >

th style = "text-align:right;" >< / th > >

th style = "text-align:right;" > / th >

th style = "text-align:right;" > / th >

th style = "text-align:right;" > / th >

/ tr >

tr style = "border:1px solid silver;text-align:right;" >

th > / th >

td > / td >

td > / td >

td > / td >

/ tr >

tr style = "border:1px solid silver;text-align:right;" >

th > / th >

td > / td >

td > / td >

td > / td >

/ tr >

tr style = "border:1px solid silver;text-align:right;" >

th > / th >

td > / td >

td > / td >

td > / td >

/ tr >

/ table >



#lang racket



(require xml)



(define xexpr

`(html

(head)

(body

(table

(tr (td) (td "X") (td "Y") (td "Z"))

,@(for/list ([i (in-range 1 4)])

`(tr (td ,(~a i))

(td ,(~a (random 10000)))

(td ,(~a (random 10000)))

(td ,(~a (random 10000)))))))))



(display-xml/content (xexpr->xml xexpr))



(formerly Perl 6)

The below example is kind of boring, and laughably simple. For more interesting/complicated examples see:

Show_Ascii_table#Raku - (simple)

Mayan_numerals#Raku - (heavy styling)

Rosetta_Code/Count_examples/Full_list - (multi-column sortable)

Rosetta_Code/List_authors_of_task_descriptions/Full_list - (complex nested tables)

Note: the above examples are outputting wikitable formatting, not HTML directly. It's pretty much a one-for-one shorthand notation though and the principles and process are the same.



This is certainly not the only or best way to generate HTML tables using Raku; just an example of one possible method.

my @header = < ; X Y Z >;

my $rows = 5 ;



sub tag ( $tag , $string , $param ? ) { return "<$tag" ~ ( $param ?? " $param" !! '' ) ~ ">$string" ~ "</$tag>" } ;



my $table = tag ( 'tr' , ( tag ( 'th' , $_ ) for @header ) ) ;



for 1 .. $rows -> $row {

$table ~= tag ( 'tr' , ( tag ( 'td' , $row , 'align="right"' )

~ ( tag ( 'td' , ( ^ 10000 ) . pick , 'align="right"' ) for 1 ..^ @header ) ) ) ;

}



say tag ( 'table' , $table , 'cellspacing=4 style="text-align:right; border: 1px solid;"' ) ;

Output:

X Y Z 1 2179 4778 2717 2 2160 1592 4348 3 4511 540 7187 4 3484 5882 1273 5 1310 4017 410

import IO;

import util::Math;



str html(str title, str content) = item("html", item("title", title) + item("body", content));

str item(str op, str content) = "\<<op>\><content>\</<op>\>";

str table(str content) = item("table border=\"0\"", content);

str tr(str content) = item("tr", content);

str td(str content) = item("td", content);



public str generateTable(int rows){

int i(){return arbInt(10000);};

rows = (tr(td("")+td("X")+td("Y")+td("Z"))

| it + tr(td("<x>")+td("<i()>")+td("<i()>")+td("<i()>"))

| x <- [1..rows]);

writeFile(|file:///location|,

html("Rosetta Code Table", table(rows)));

return "written";

}

This will result in a simple html file. For example:

rascal>generateTable(10)

str: "written"

Output:

<html><title>Rosetta Code Table</title><body><table border="0"><tr><td></td><td>X</td><td>Y</td><td>Z</td></tr><tr><td>1</td><td>253</td><td>3988</td><td>3208</td