cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar
Craige_Hales
Super User
Create HTML table from JSL

Recently I needed to do some web scraping to figure out parts availability. I used JMP to sift through the data and make a web page. This JSL is a simplified version of that web page generator. It creates an HTML directory in your computer's $TEMP space and adds some graphics using JMP's maps. At the same time, it builds a data table with links to the images.

Clicking the link in the data table opens another window; the table is moved back in front for this illustration.Clicking the link in the data table opens another window; the table is moved back in front for this illustration.

To make a web page that looks pretty, I went to a randomly selected online table generating site, did some color customizations, and grabbed the sample CSS and HTML to paste into the JSL. After a few minutes of studying, I cut it apart so the repetitive table body lines can be created from JSL. You can run the JSL unchanged and it will open a browser to the file-based site in your temp directory, or you can see it here.

// example web page creation
// step 0: make a place to keep the web site
htmlDir = "$temp/html/";
Delete Directory( htmlDir );
Create Directory( htmlDir );

// step 1, build a JMP table, pictures, links.
positions = {{"North Carolina", -84, -76, 33.5, 37}, {"Virginia", -83.4, -75.3, 36.1, 39.7}, {"Kentucky", -89.8, -81.4, 36, 39.6}, {"Tennessee", -90,-81.6, 34.2, 37.8}};
maps = {Images( "Detailed Earth" ), Images( "NASA server" ), Images( "Street Map Service", "Mapbox Light", "" )};
copyright = {"", "", "© Mapbox © OpenStreetMap"};
maptype = Function( {i}, Regex( Char( maps[i] ), "\!"([^\!"]*)", "\1" ) );//  text between the first two quotation marks - just the quoted string part

dtBC = Open( "$sample_data/big class.jmp" ); // not using the data in the maps, just need to open graph builder with a table

// this expression will be used in loops below to make graphs by substituting _backgroundimage_() and by using variables iPos and iMap
gbExpr = Expr(
	dtBC << Graph Builder( Size( 840 * 2, 411 * 2 ), Show Control Panel( 0 ), Show Legend( 0 ), Variables( X( :weight ), Y( :height ) ),
		Elements( Points( X, Y, Legend( 3 ) ), Smoother( X, Y, Legend( 4 ) ) ),
		SendToReport(
			Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( "" ), Image Export Display( Normal )} ),
			Dispatch( {}, "weight", ScaleBox,
				{Scale( "Geodesic", {Compact Map( {Region( "United States" ), Alaska( 1 ), Hawaii( 1 ), Puerto Rico( 1 )} )} ), Format( "Best", 9 ),
				Min( positions[iPos][2] ), Max( positions[iPos][3] ), Inc( 2 ), Minor Ticks( 1 ), Label Row(
					{Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Ticks( 0 )}
				)}
			),
			Dispatch( {}, "height", ScaleBox,
				{Scale( "Geodesic", {Compact Map( {Region( "United States" ), Alaska( 1 ), Hawaii( 1 ), Puerto Rico( 1 )} )} ),
				Min( positions[iPos][4] ), Max( positions[iPos][5] ), Inc( 0.5 ), Minor Ticks( 0 ), Label Row(
					{Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Ticks( 0 )} )} ),
			Dispatch( {}, "graph title", TextEditBox, {Set Text( positions[iPos][1] )} ),
			Dispatch( {}, "X title", TextEditBox, {Set Text( copyright[iMap] )} ),
			Dispatch( {}, "Y title", TextEditBox, {Set Text( "" )} ),
			Dispatch( {}, "Graph Builder", FrameBox,
				{Background Color( 60 ), Background Map( _backgroundimage_(), Boundaries( "US States" ) ), DispatchSeg( MapSeg( 1 ),
					{Clip Shape( Boundaries( "US States", ID( positions[iPos][1] ) ) )} )} )
		)
	)
);

// open a new table. Give it clickable columns within JMP.

dt = New Table( "places",
	addrows( N Items( positions ) ),
	New Column( "name", character ),
	New Column( maptype( 1 ),
		Character,
		"Nominal",
		Set Property(
			"Event Handler",
			Event Handler(
				Click( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },Web( Char( thisTable:thisColumn[ iRow ] ) ); );) ),
				Tip( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },"Open " || Char( thisTable:thisColumn[ iRow ] ) || " in browser."; );) ),
				Color( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },RGBColor("link"); );) )
			)
		)
	),
	New Column( maptype( 2 ),
		Character,
		"Nominal",
		Set Property(
			"Event Handler",
			Event Handler(
				Click( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },Web( Char( thisTable:thisColumn[ iRow ] ) ); );) ),
				Tip( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },"Open " || Char( thisTable:thisColumn[ iRow ] ) || " in browser."; );) ),
				Color( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },RGBColor("link"); );) )
			)
		)
	),
	New Column( maptype( 3 ),
		Character,
		"Nominal",
		Set Property(
			"Event Handler",
			Event Handler(
				Click( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },Web( Char( thisTable:thisColumn[ iRow ] ) ); );) ),
				Tip( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },"Open " || Char( thisTable:thisColumn[ iRow ] ) || " in browser."; );) ),
				Color( JSL Quote(Function( {thisTable, thisColumn, iRow}, {  },RGBColor("link"); );) )
			)
		)
	)
);

// loop over states and map types to fill in the table

For( iPos = 1, iPos <= N Items( positions ), iPos += 1,
	dt:name[iPos] = positions[iPos][1];
	For( iMap = 1, iMap <= N Items( maps ), iMap += 1,
		gb = Eval( Substitute( Name Expr( gbExpr ), Expr( _backgroundimage_() ), maps[iMap] ) );
		img = gb << getpicture;
		path = htmlDir || Regex( positions[iPos][1] || maptype( iMap ), " ", "", globalreplace ) || ".jpg";
		img << savepicture( path, "jpg" );
		Column( dt, maptype( iMap ) )[iPos] = path;
		gb << closewindow;
	);
);

// at this point, the data table has clickable links. But there is no option to save it as HTML.
// visit https://www.tablesgenerator.com/html_tables to make a style sheet for a table of 4 columns, paste it here.
// mostly we need the style sheet, but we also need to see how the styles connect to the html elements.
// carve it up into snips of JSL that can be reused:

style =
"\[
<style type="text/css">
.tg  {border:none;border-collapse:collapse;border-color:#9ABAD9;border-spacing:0;}
.tg td{background-color:#EBF5FF;border-color:#9ABAD9;border-style:solid;border-width:0px;color:#444;
  font-family:Arial, sans-serif;font-size:14px;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{background-color:#409cff;border-color:#9ABAD9;border-style:solid;border-width:0px;color:#fff;
  font-family:Arial, sans-serif;font-size:14px;font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-phtq{background-color:#D2E4FC;border-color:inherit;text-align:left;vertical-align:top}
.tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top}
.tg .tg-f8tv{border-color:inherit;font-style:italic;text-align:left;vertical-align:top}
.tg .tg-6gib{background-color:#D2E4FC;border-color:inherit;font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-fymr{border-color:inherit;font-weight:bold;text-align:left;vertical-align:top}
</style>
]\";
header =
"\[
<table class="tg">
<thead>
  <tr>
    <th class="tg-0pky">State</th>
    <th class="tg-f8tv">Detailed Earth</th>
    <th class="tg-f8tv">NASA Server</th>
    <th class="tg-f8tv">StreetMap Service</th>
  </tr>
</thead>
<tbody>
]\";
evenrow =
"\[
  <tr>
    <td class="tg-6gib">^dt:name[row()]^</td>
    <td class="tg-phtq">^detail_earth^</td>
    <td class="tg-phtq">^nasa_server^</td>
    <td class="tg-phtq">^streetmap_service^</td>
  </tr>
]\";
oddrow =
"\[  
  <tr>
    <td class="tg-fymr">^dt:name[row()]^</td>
    <td class="tg-0pky">^detail_earth^</td>
    <td class="tg-0pky">^nasa_server^</td>
    <td class="tg-0pky">^streetmap_service^</td>
  </tr>
]\";
trailer = "\[ 
</tbody>
</table>
]\";

// use a picture for the link, include the 2-letter state name as text in the link

abrev=["North Carolina"=>"NC", "Virginia"=>"VA","Kentucky"=>"KY","Tennessee"=>"TN"];
pic = Function( {url, txt, abr},
	Eval Insert( "\[<img src="^url^" width="100" height="50" alt="^txt^" /><br>^abr^]\" )
);

// split the path name into overlapping txt and url parts
pat = Pat Arb() + "html/" + (Pat Break( "." ) >> txt + Pat Rem()) >> url; // url is the whole value, txt is just the remainder after "html/"
// url include .jpg extension. txt is for display and does not show extension

// assemble the html body text into a long string

bodytext = style || header;
For Each Row(
	dt,
	Pat Match( dt:"detailed earth"n[Row()], pat );
	detail_earth = Eval Insert( "\[<a href="^url^">^pic(url,txt,abrev[dt:name[row()]])^</a>]\" );
	Pat Match( dt:"nasa server"n[Row()], pat );
	nasa_server = Eval Insert( "\[<a href="^url^">^pic(url,txt,abrev[dt:name[row()]])^</a>]\" );
	Pat Match( dt:"street map service"n[Row()], pat );
	streetmap_service = Eval Insert( "\[<a href="^url^">^pic(url,txt,abrev[dt:name[row()]])^</a>]\" );
	bodytext ||= Eval Insert( If( Mod( Row(), 2 ) == 0, evenrow, oddrow ) );
);
bodytext ||= trailer;

bodytext ||= "\[<br><br><a href="https://community.jmp.com/t5/Uncharted/Create-HTML-table-from-JSL/ba-p/613288">More info</a><br>]\";

// wrap the rest of the web page around the body text

html = Eval Insert( "\[
<!DOCTYPE html>
<html>
  <head>
    <title>Pictures of States</title>
  </head>
  <body>
	^bodytext^
  </body>
</html>	
]\" );

// save and display

file = Save Text File( htmlDir || "states.html", html );
Web( file );

It is a picture of links, not actual links.It is a picture of links, not actual links.

Last Modified: Mar 16, 2023 8:14 PM