Friday, July 14, 2017

Inserting A Date Stamp into HTML Documents

Introduction

In Using Node.js for Text Processing, I showed you how a simple method to use Node.js processing content of HTML files. In this tutorial, I'll show you another technique for adding content to HTML files using Node.js as a command line interface (CLI) by supplying a script with arguments (flags), set up a basic help message, and append a date stamp to an user supplied HTML file. If this is your tune, let's jam!

Requirements

You should be fairly comfortable with JavaScript in general and have some working knowledge of how Node.js works prior to digging into this tutorial.

Required npm packages

In this tutorial, we'll need to ensure the following packages have been install in your project directory: 
Note: This tutorial was written with Node.js (version  ~0.12.7).

Building the script

First off, let's create a new file called append_date.js. As with any typical Node.js script, we start off with a few variables requiring our packages:

var fs = require('fs');
var cheerio = require('cheerio');
var program = require('commander');
...


In this snippet, we use fs to read in the target file, cheerio to manipulate the content with jQuery-like features, and commander for the CLI features of our script. Commander is a wonderful library that I recently discovered and works very well with my documentation and web developing needs.

Setting up the CLI

Like any well written CLI, we should start off with defining how it works. In the following snippet, we define the version of the CLI, how to use it (.usage), and any options (.option) available to the user. Commander is kind enough to provide a basic help output if the user types in <command> -h/--help as well as any usage and options you provide. Commander will display the default help message plus any info defined in the snippet below:

...
program
  .version('0.0.3')
  .usage('[required options] -t <path/file.html> -d <date>')
  .option('-t, --target [target]', '*required* target of HTML file (including the path and file name)')
  .option('-d, --date [date]', '*required* date to append to the HTML file')
  .parse(process.argv);
...

Main processing

Next, we check if both the target file and date flags have been supplied. From there, the script will load the target file and convert it to a string. The script will next check to see if a container element (div#content) exist and decide to create or update it. If the div#content element exists, the script will then look to either create or update the span.date element. With the elements in place, the script will now write out the updated HTML file.

...
if (program.target && program.date) {
  console.log('Updating ' + program.target);
  $ = cheerio.load(fs.readFileSync(program.target).toString()); // load file and convert it to a string

  if ($('div#content').length <= 0) { // if div#content doesn't exist, create it
    console.log(program.target + ' does not have div#content element. Adding it and datestamp now.');
    $('body').append('\t<div id="content">\n\t\t\t<span class="date">Last updated: ' + program.date + '</span>\n\t\t</div>\n\t');
  } else { // if div#content exists, look for span.date
    console.log(program.target + ' has div#content element; looking for date stamp')
    if ($('span.date')) { // if the span.date exists, update it
      console.log(program.target + ' has span.date element; updating it now');
      $('span.date').text('Last updated: ' + program.date);
    } else { // span.date doesn't exist; create it
      console.log(program.target + ' dos not have span.date element; adding it now');
      $('div#content').append('\t<span class="date">Last updated: ' + program.date + '</span>\n\t\t'); // add date under the content div
    }
  }

  var updated = $.html(); // collect updated html content
  fs.writeFileSync(program.target,updated); // save out updated HTML file
...



Fail checks

Like any good CLI, it should fail gracefully by informing the user that something was missing or failed in some way. To accomplish that, our script should check if the target and date flags were not filled out as they will be required for the script to carry out it's purpose. In the following code snippet, the first else if statement confirms if the target file wasn't supplied by the user. The second else if statement confirms if the user supplied a date flag. The final else statement is a catch all if something goes skips a beat.

...
} else if (!program.target) {
  console.log('Target for the HTML file was not provided; quitting.');
  process.exit(1);
} else if (!program.date) {
  console.log('No date stamp was provided; quitting');
  process.exit(1);
} else {
  console.log('undefined error; quitting');
  process.exit(1);
}

This completes the script. At this point, we should save the file and call it appendDate.js.

Note: this script doesn't verify the date string you enter into the span.date element. You could add a check for the program.date content to conform to a specific format using Regex (like /(\d[0-9]){2}-(\d[0-9]{1})-(\d[0-9]{1})/g) but that is entirely up to you.

CLI in action

With script completed, lets test it out on a simple HTML file. Copy the following code and save the file name as test.html in the same directory as your node script:

<!DOCTYPE html>
<html>
<head>
  <title>Date Stamp Test</title>
</head>
<body>
</body>
</html>


Let's test our script by executing the following command: node appendDate.js -t test.html -d 2017-03-30 (or whatever date string you wish to use). Examine the test.html. You should see our date stamp appended to the document with our custom date stamp.


Review

In ~40 lines of code, we created a script that takes arguments from the command line for a target file and a date string, loaded the target file, modified the target file with the date string, and wrote out the target file with the update HTML.

I hope this tutorial was useful and thank you for reading it.

No comments:

Post a Comment