The Python HTMLgen Module
This article is about using HTMLgen, a Python-class library for generating HTML. Python is an object-oriented scripting language that ships with most Linux distributions. It plays a major role in configuration and management for distributions such as Caldera and Red Hat. HTMLgen is an add-on Python module written by Robin Friedrich, and available from http://starship.python.net/lib.html under a BSD-style freeware license.
HTMLgen provides classes to support all the standard HTML 3.2 tags and attributes. It can be used in any situation where you need to dynamically generate HTML. For example, you might want to format the results of a database query into an HTML table, or generate an HTML order form customized for each client.
I'll introduce HTMLgen by using it to format data found on typical Linux systems. I think the examples are sufficiently straightforward that they can be followed by anyone familiar with HTML and scripting, and without prior knowledge of Python. Just remember that in Python, blocks of statements are indicated by indenting the code—there are no begin/end statements and no curly braces. (In Python, WYSIWYG applies.) Other than this, Python code looks much like that found in any mainstream programming language.
Although Perl is the most commonly used web scripting language, I personally prefer Python. It can achieve results similar to Perl, and I think Python's syntax, coupled with the style established by its user community, leads to a cleaner, simpler style of coding. This is an advantage during both development and maintenance. These same strengths provide a gentler learning curve for new players. Python moves a little away from traditional scripting languages and more toward non-scripting, procedural programming languages. This allows Python scripting to scale well. When a small set of scripts starts to grow to the size of a full-blown application system, the language will support the transition.
Any Python program needing HTMLgen must import it as a module. Starting from bash, here's how I set up and import HTMLgen to create a “Hello World” web page:
bash$ export PYTHONPATH=/local/HTMLgen:$PYTHONPATH bash$ python >>> import HTMLgen >>> doc = HTMLgen.SimpleDocument(title="Hello") >>> doc.append(HTMLgen.Heading(1, "Hello World")) >>> print doc
First, I set the PYTHONPATH to include the directory where the HTMLgen.py module can be found. Then, I start the Python interpreter and use its command-line interface to import the HTMLgen module. I create a document object called doc and add a heading to it.
Finally, I print the doc object which dumps the following HTML to standard output:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <HTML> <!-- This file generated using HTMLgen module. --> <HEAD> <META NAME="GENERATOR" CONTENT="HTMLgen 2.0.6"> <TITLE>Hello World</TITLE> </HEAD> <BODY> <H1>Hello World</H1> </BODY> </HTML>
Figure 1. Table—Code in Listing 1
This is a start, although not an exciting one. HTMLgen is a very good tool for generating HTML tables and lists. The table in Figure 1 was created by the Python script in Listing 1. The data in the table comes from the Linux /proc/interrupts file which details the IRQ interrupts for your Linux PC. On my PC, doing a cat of /proc/interrupts yields:
0: 2348528 timer 1: 42481 keyboard 2: 0 cascade 3: 47735 + serial 4: 75428 + serial 5: 48 soundblaster 8: 0 + rtc 11: 1 NE2000 13: 1 math error 14: 175816 + ide0 15: 216 + ide1
The Python script reads the contents of the /proc/interrupts file and copies the data into an HTML table. I'll describe this process step by step. As in the previous example, I first create a simple document. I then add an HTMLgen table to the document:
table = HTMLgen.Table( tabletitle='Interrupts', border=2, width=100, cell_align"right", heading=[ "Description", "IRQ", "Count" ]) doc.append(table)When creating the table object, I set some optional attributes by supplying them as named arguments. The final headings argument sets the list of column headings that HTMLgen will use. All of the above arguments are optional.
Once I've set up my table, I open the /proc/interrupts file and use the readlines method to read in its entire contents. I use a for loop to step through the lines returned and turn them into table rows. Inside the loop, the string and regular expressions functions are used to strip off leading spaces and split up each line into a list of three data values based on space and colon (:) separators:
data=regsub.split(string.strip(line),'[ :+]+')
Elements of the data list are processed to form a table row by reordering them into a new three-element list consisting of name, number and total calls:
[ HTMLgen.Text(data[2]), data[0], data[1] ]The outer enclosing square brackets construct a list out of the comma-separated arguments. The first list element, data[2], is the interrupt name. The interrupt name is a non-numeric field, so I've taken the precaution of escaping any characters that might be special to HTML by passing it though the HTMLgen Text filter. The resulting list is made into a row of the table by appending the list to the table's body:
table.body.append(
[ HTMLgen.Text(data[2]), data[0], data[1] ])
Finally, once all lines have been processed, the document is
written to interrupts.html. The result is shown in Figure 1.
The simple Table class is designed for displaying rows of data such as might be returned from a database query. For more sophisticated tables, the TableLite object offers a lower-level table construction facility that includes the ability to do individual row/column customization, column/row spanning and nested tables.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- A Topic for Discussion - Open Source Feature-Richness?
- RSS Feeds
- Drupal Is a Framework: Why Everyone Needs to Understand This
- Validate an E-Mail Address with PHP, the Right Way
- Readers' Choice Awards
- Tech Tip: Really Simple HTTP Server with Python
- Reply to comment | Linux Journal
23 min 26 sec ago - All the articles you talked
2 hours 47 min ago - All the articles you talked
2 hours 50 min ago - All the articles you talked
2 hours 51 min ago - myip
7 hours 16 min ago - Keeping track of IP address
9 hours 7 min ago - Roll your own dynamic dns
14 hours 20 min ago - Please correct the URL for Salt Stack's web site
17 hours 32 min ago - Android is Linux -- why no better inter-operation
19 hours 47 min ago - Connecting Android device to desktop Linux via USB
20 hours 15 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




Comments
Re: The Python HTMLgen Module
Hello Michael
I read your article on "http://www.linuxjournal.com/article.php?sid=2986" regarding making barchart using HTMLgen , i was in need of that thing and your article has helped me a lot , but the bar chart also displays the AVERAGE of the data supplied to it and also display average graphically. Is there any way that i can remove the average part and my bar chart will not display the average bar.
Waiting for your reply.... at nitinparikh2000@yahoo.com
Thanks and Regards
Nitin Parikh
Pune , India