DaemonForums  

Go Back   DaemonForums > Miscellaneous > Guides

Guides All Guides and HOWTO's.

Reply
 
Thread Tools Display Modes
  #1   (View Single Post)  
Old 12th September 2008
J65nko J65nko is online now
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 3,263
Thanked 182 Times in 149 Posts
Default A XHTML makeover of 'vmstat -iz' output by cosmetic surgeons Dr. XML and Dr. XSLT

A XHTML makeover of 'vmstat -iz' output by cosmetic surgeons Dr. XML and Dr. XSLT
  • 1.1 Abstract
  • 1.2 The plain text output from 'vmstat -iz'
  • 1.3 The 'vmstat2xml.sed' command file for 'sed(1)'
  • 1.4 Dr. XML's part in the makeover
  • 1.5 The XSL stylesheet from Dr. XSLT
  • 1.6 Applying the XSL stylesheet in a browser
  • 1.7 Using Xalan-c for the XSLT transformation
  • 1.8 Using Sablotron for the XSLT transformation
  • 1.9 Resources
  • 1.10 Epilogue




1.1 Abstract

This guide or tutorial will show how to convert plain text output of the OpenBSD vmstat -iz command to XML, using 'sed', the Unix stream editor. The XML formatted data will be the source for a XSLT transformation into XHTML.

The XSLT transformation will be done according to the transformation templates of the presented XSL stylesheet.

The conversion of the XML file into XHTML will be done by an XSLT processor, for example by the built-in XSLT engine of Firefox. From the standalone XSLT processors, the usage of Sablotron and Xalan will be demonstrated.




1.2 The plain text output from 'vmstat -iz'

According to the OpenBSD man page for 'vmstat' this program "reports certain kernel statistics kept about process, virtual memory, disk, trap, and CPU activity"

The '-i' option "reports on the number of interrupts (traps) taken by each device since system startup", while the '-z' option also "lists devices which have not yet generated an interrupt".

Code:
$ ssh j65nko@parmenides 'vmstat -iz' >vmstat.txt
$ cat vmstat.txt

interrupt                       total     rate
irq14/pciide0                  179284        0
irq11/uhci0                         0        0
irq10/xl0                     5115342        2
irq12/fxp0                    4880752        2
irq1/pckbc0                      4981        0
irq7/lpt0                           0        0
irq4/pccom0                         0        0
irq3/pccom1                         0        0
irq6/fdc0                           0        0
irq5/wss1                           0        0
irq9/mpu0                           0        0
irq0/clock                  243870818       99
irq8/rtc                    312161132      127
Total                       566212309      232
Our ultimate goal is to make this plain text output look like this. We will do this by first converting the text to XML, which will be the base for the transformation into (X)HTML.

The XML version looks like this:

Code:
<?xml version='1.0' encoding='UTF-8' ?>
<?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?>

<!--     generated by 'sed(1)'   -->

<vmstat-i>
  <irq nr='14' dev='pciide0' total="179284" rate="0" />
  <irq nr='11' dev='uhci0' total="0" rate="0" />
  <irq nr='10' dev='xl0' total="5115342" rate="2" />
  <irq nr='12' dev='fxp0' total="4880752" rate="2" />
  <irq nr='1' dev='pckbc0' total="4981" rate="0" />
  <irq nr='7' dev='lpt0' total="0" rate="0" />
  <irq nr='4' dev='pccom0' total="0" rate="0" />
  <irq nr='3' dev='pccom1' total="0" rate="0" />
  <irq nr='6' dev='fdc0' total="0" rate="0" />
  <irq nr='5' dev='wss1' total="0" rate="0" />
  <irq nr='9' dev='mpu0' total="0" rate="0" />
  <irq nr='0' dev='clock' total="243870818" rate="99" />
  <irq nr='8' dev='rtc' total="312161132" rate="127" />
  <summary grandtotal='566212309' grate='232' />
</vmstat-i>
The 'vmstat-i' is the XML root element. It has multiple 'irq' elements as children, while the data like 'nr', 'dev', 'total' and 'rate' is stored in attributes with those names.

Another possible valid XML format, although more bulky, would be:

Code:
<vmstat-i>
   <irq>
      <nr>14</nr>
      <dev>pciide0</dev>
      <total>179284</total>
      <rate>0</rate> 
   </irq>

   <irq>
     ...... 
   </irq>
</vmstat-i>
But for the fixed table like data we are working with, the first format will do fine.




1.3 The 'vmstat2xml.sed' command file for 'sed(1)'

The conversion to XML is simple enough to be done by 'sed'.

Code:
 1  # -- sed command file to XMLize 'vmstat -iz' output
 2  
 3  1c\
 4  <?xml version='1.0' encoding='UTF-8' ?>\
 5  <?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?>\
 6  \
 7  <!--     generated by 'sed(1)'   -->\
 8  \
 9  <vmstat-i>
10  
11  s~irq\([0-9][0-9]*\)/\([^ ][^ ]*\)  *\([0-9][0-9]*\)  *\([0-9][0-9]*\)~  <irq nr='\1' dev='\2' total="\3" rate="\4" />~
12  
13  ${
14  s~^[Tt]otal  *\([0-9][0-9]*\)  *\([0-9][0-9]*\)~  <summary grandtotal='\1' grate='\2' />~p
15  a\
16  </vmstat-i>
17  }
There are three commands in this file.
  1. A change command for the first line (lines 3-9), which changes the first line into the XML header.
  2. Line 11 is a search and replace command for the the 'irq' data
  3. A command applicable to the last line, which handles the totals and the closing of the XML root element (line 11-17)

According to the man page, The format of a sed command is as follows:

Code:
[address[,address]]function[arguments]
The description of the change command/function:

Code:
     [2addr]c\
     text

               Delete the pattern space.  With 0 or 1 address or at the end of
               a 2-address range, text is written to the standard output.


     The argument text consists of one or more lines.  To embed a newline in
     the text, precede it with a backslash.  Other backslashes in text are
     deleted and the following character taken literally
The 'change' function is:

Code:
 3  1c\
 4  <?xml version='1.0' encoding='UTF-8' ?>\
 5  <?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?>\
 6  \
 7  <!--     generated by 'sed(1)'   -->\
 8  \
 9  <vmstat-i>
In this case the '1' is the '[2addr], the 'c\' is the change command, and lines 4-9 is the text.

If we copy lines 3-9 to the file 'cmd-1' we get the following result:

Code:
$ sed -ne '3,9p' vmstat2xml.sed >cmd-1
$ sed -f cmd-1 vmstat.txt
   
<?xml version='1.0' encoding='UTF-8' ?>
<?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?>

<!--     generated by 'sed(1)'   -->

<vmstat-i>
irq14/pciide0                  179284        0
irq11/uhci0                         0        0
irq10/xl0                     5115342        2
[output snipped]
irq0/clock                  243870818       99
irq8/rtc                    312161132      127
Total                       566212309      232
The original first line: 'interrupt total rate', the table header, has been changed into the leading XML declarations.

The second command has to change

Code:
irq14/pciide0                  179284        0
into

Code:
<irq nr='14' dev='pciide0' total="179284" rate="0" />
All lines start with 'irq' followed by a a number, followed by a forward slash '/', and a device name. After some spaces we have two numbers each separated by multiple spaces

'sed' uses the Basic Regular Expressions (BRE) as described in the re_format(7) man page. sed(1) describes two 'sed' specific additions to the BRE.

A short overview of the major regular expression used:
  • [0-9][0-9]* to match a digit, followed by zero or more digits.
  • \( ... \) will save the matched text in a variable or container, which can be referenced later by number.
  • [^ ][^ ]* to match a non-blank, followed by zero or more non-blanks.

The general format of search and replace: s/search_pattern/replacement/

The '/' is used a a delimiter to indicate the start and end of the search pattern and replacement text. In our case we have to match the '/' of 'irq14/pciide0'.

To match this forward slash we would have to use a backslash to escape the forward slash: '\/'. A comfortable way to avoid this 'leaning toothpick' syndrome. is to use custom delimiters. I used a tilde '~', so the format becomes: s~search_pattern~replacement~

Explanation of the regular expression:

Code:
s~irq\([0-9][0-9]*\)/\([^ ][^ ]*\)  *\([0-9][0-9]*\)  *\([0-9][0-9]*\)~

Sample text	: 'irq14/pciide0                  179284        0'

s		: substitute function

~		: custom delimiter indicating start of the search pattern
irq		: the string 'irq' 

		/* The irq number for 'irq=' attribute */
\(		: start saving in container '\1'
[0-9]		: a single digit 
[0-9]*		: optionally followed by more digits
\)		: stop saving in container '\1'

/		: a '/' which indicates start of te device name

		/* the device name for 'dev=' attribute */
\(		: start saving in next container '\2'
[^ ]		: a non-space or non-blank
[^ ]*		: optionally followed by more non-blanks
\)		: stop saving in container '\2'

  *		: a space, optionally followed by more spaces

		/* total number of interrupts for 'total=' attribute */
\(		: start saving in next container '\3'
[0-9]		: a single digit 
[0-9]*		: optionally followed by more digits
\)		: stop saving in container '\3'

  *		: a space, optionally followed by more spaces

		/* the interrupt rate for 'rate=' attribute */
\(		: start saving in next container '\4'
[0-9]		: a single digit 
[0-9]*		: optionally followed by more digits
\)		: stop saving in container '\4'

~		: end of search pattern, start of substitution
The replacement:

Code:
  <irq nr='\1' dev='\2' total="\3" rate="\4" />~

  <irq 		: 2 leading blanks and the text '<irq '

nr='\1'		: the string 'nr=', a single quote, contents of
		  container '\1', a single quote and blank

dev='\2'	: the string 'dev=',  a single quote, contents of
		  container '\2', a single quote and blank

total="\3"	: the string 'total=', a double quote, contents of
		  container '\3', a double quote and blank

rate="\4"	: the string 'rate=', a double quote, contents of
		  container '\4', a double quote and blank

/>		: the string '/>' closing the XML element 'irq'

~		: end of replacement pattern
Copying this search and replace to the file 'cmd-2' we get the following result:

Code:
$ sed -ne '11p' vmstat2xml.sed  >cmd-2
$ sed -f cmd-2 vmstat.txt
interrupt                       total     rate
  <irq nr='14' dev='pciide0' total="179284" rate="0" />
  <irq nr='11' dev='uhci0' total="0" rate="0" />
  <irq nr='10' dev='xl0' total="5115342" rate="2" />
  [snip]
  <irq nr='9' dev='mpu0' total="0" rate="0" />
  <irq nr='0' dev='clock' total="243870818" rate="99" />
  <irq nr='8' dev='rtc' total="312161132" rate="127" />
Total                       566212309      232
The third 'sed' function will convert the last line with the totals and properly close the XML root element 'vmstat-i'.

Code:
13  ${
14  s~^[Tt]otal  *\([0-9][0-9]*\)  *\([0-9][0-9]*\)~  <summary grandtotal='\1' grate='\2' />~
15  a\
16  </vmstat-i>
17  }
The $ means the last line, all commands between the opening '{' and closing '}' will be applied to this line.

The first command (line 14) is a search and replace command. Lines 15-16 is an append function, which simple glues a terminating '</vmstat-i>' to the end of the output.

The search part:

Code:
s~^[Tt]otal  *\([0-9][0-9]*\)  *\([0-9][0-9]*\)~

Sample text	: 'Total                       566212309      232'	

s               : substitute function

~               : custom delimiter indicating start of the search pattern
[Tt]		: a 'T' or a 't' (an attempt of defensive programming)
otal		: the string 'otal'
  *		: a space, optionally followed by more spaces

		/* the total number of interrupts */
\(              : start saving in container '\1'
[0-9]           : a single digit 
[0-9]*          : optionally followed by more digits
\)              : stop saving in container '\1'

  *		: a space, optionally followed by more spaces

		/* the average rate of interrupts */
\(              : start saving in container '\2'
[0-9]           : a single digit 
[0-9]*          : optionally followed by more digits
\)              : stop saving in container '\2

~               : end of search pattern, start of substitution
The replacement:

Code:
~  <summary grandtotal='\1' grate='\2' />~

 <summary	: 2 leading blanks and the string ' <summary '
grandtotal='\1'	: the string 'grandtotal=', a single quote, contents of
		  container '\1', a single quote and blank

grate='\2'	: the string 'grate=', a single quote, contents of 
		  container '\2', a single quote and blank

/>		: the string '/>' closing the XML element 'summary'

~               : end of replacement pattern
Copying this last command of lines 13-17 to the file 'cmd-3' and having 'sed' execute it:

Code:
$ sed -ne 13,17p vmstat2xml.sed >cmd-3
$ sed -f cmd-3 vmstat.txt

interrupt                       total     rate
irq14/pciide0                  179284        0
irq11/uhci0                         0        0
[snip]
irq0/clock                  243870818       99
irq8/rtc                    312161132      127
  <summary grandtotal='566212309' grate='232' />
<vmstat-i>




1.4 Dr. XML's part in the makeover

Depending on the circumstances Dr. XML chooses one of the following procedures:
  1. Feeding the output of 'vmstat' directly to 'sed'.

    Code:
    $ vmstat -iz | sed -f vmstat2xml.sed  >vmstat-iz.xml
  2. Saving the 'vmstat' output in an intermediate file, which is then fed to 'sed'.

    Code:
    $ vmstat -iz >vmstat-iz.txt
    $ sed -f vmstat2xml.sed  <vmstat-iz.txt >vmstat-iz.xml
Both methods produce the same result:

Code:
<?xml version='1.0' encoding='UTF-8' ?>
<?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?>

<!--     generated by 'sed(1)'   -->

<vmstat-i>
  <irq nr='14' dev='pciide0' total="179284" rate="0" />
  <irq nr='11' dev='uhci0' total="0" rate="0" />
  <irq nr='10' dev='xl0' total="5115342" rate="2" />
  <irq nr='12' dev='fxp0' total="4880752" rate="2" />
  <irq nr='1' dev='pckbc0' total="4981" rate="0" />
  <irq nr='7' dev='lpt0' total="0" rate="0" />
  <irq nr='4' dev='pccom0' total="0" rate="0" />
  <irq nr='3' dev='pccom1' total="0" rate="0" />
  <irq nr='6' dev='fdc0' total="0" rate="0" />
  <irq nr='5' dev='wss1' total="0" rate="0" />
  <irq nr='9' dev='mpu0' total="0" rate="0" />
  <irq nr='0' dev='clock' total="243870818" rate="99" />
  <irq nr='8' dev='rtc' total="312161132" rate="127" />
  <summary grandtotal='566212309' grate='232' />
</vmstat-i>
After understanding how 'sed' edits the text output into XML format, we will now turn out attention to the XSL stylesheet which contains the templates to transform the XML into XHTML.




1.5 The XSL stylesheet from Dr. XSLT

For the repeating cosmetic makeovers Dr. XSLT has created the following XSL stylesheet:

Code:
 1  <?xml version="1.0" encoding='UTF-8' ?>
 2  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
 3  
 4  <!-- $Id:  vmstat-i.xsl,v 1.2 2008/08/26 23:40:43 j65nko Exp $ -->
 5  
 6  <xsl:output
 7      method='html'
 8      omit-xml-declaration='no'
 9      indent='yes' 
10      standalone='yes'
11      doctype-public='-//W3C//DTD XHTML 1.0 Strict//EN'
12      doctype-system='http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
13  />
14  
15  <xsl:template match="/vmstat-i" >
16    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"  >
17      <head>
18        <title>vmstat -i</title>
19        <style type="text/css" >
20          <xsl:call-template name="stylesheet"/>
21        </style>
22      </head>
23      <body>
24        <table>
25          <xsl:call-template name="table-header" />
26          <xsl:apply-templates select="irq">
27            <!-- sort by IRQ number low to high -->
28            <xsl:sort select='@nr' data-type='number' order='ascending' /> 
29            <!-- with identical, shared IRQ, show highest total first -->
30            <xsl:sort select='@total' data-type='number' order='descending' /> 
31          </xsl:apply-templates> 
32          <xsl:call-template name="total" />
33        </table>
34      </body>
35    </html>
36  </xsl:template>
37  
38  <xsl:template match="irq">
39  <tr>
40    <td class='nr'>   <xsl:value-of select="@nr"/>    </td>
41    <td class='text'> <xsl:value-of select="@dev"/>   </td>
42    <td class='nr'>   <xsl:value-of select="format-number(@total,'#,###')"/> </td>
43    <td class='nr'>   <xsl:value-of select="format-number(@rate,'#,###')" /> </td>
44  </tr>
45  </xsl:template>
46  
47  <xsl:template name="stylesheet" > 
48    .nr   { text-align: right; background-color: rgb(220,220,200); padding: .5em; }
49    .text { text-align: left;  background-color: rgb(220,200,200); padding: .5em; }
50    .hr   { text-align: right; background-color: silver ; padding: .5em; }
51  </xsl:template>
52  
53  <xsl:template name="table-header" > 
54    <tr>
55      <td class='hr' style="text-align: center" colspan='4' >I n t e r r u p t s</td>
56    </tr>
57    <tr>
58      <td class='hr'>IRQ</td>
59      <td class='hr'>Device</td>
60      <td class='hr'>Total</td>
61      <td class='hr'>Rate</td>
62    </tr>
63  </xsl:template>
64  
65  <xsl:template name="total" > 
66  <tr>
67    <td class='hr' colspan='2' >T o t a l</td>
68    <td class='hr'><xsl:value-of select='format-number(sum(//@total),"#,###")' /> </td>
69    <td class='hr'><xsl:value-of select='format-number(sum(//@rate), "#,###")' /> </td>
70  </tr>
71  </xsl:template>
72  
73  </xsl:stylesheet>
We will now comment on each part of this stylesheet.

Code:
 1  <?xml version="1.0" encoding='UTF-8' ?>
 2  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
 3  
 4  <!-- $Id:  vmstat-i.xsl,v 1.2 2008/08/26 23:40:43 j65nko Exp $ -->
A XSLT stylesheet is a XML document. Line 1 is the XML declaration stating the XML version and the character encoding.

The root element is 'xsl:stylesheet', which starts on line 2 and ends on line 73. The 'xmlns:xsl' attribute defines the version and the XSLT namespace and it's prefix 'xsl'. All XML elements prefixed with 'xsl' constitute the stylesheet.

After the comment on line 4, containing the RCS revision identifier, follows the first stylesheet element 'xsl-output'

Code:
 6  <xsl:output
 7      method='html'
 8      omit-xml-declaration='no'
 9      indent='yes' 
10      standalone='yes'
11      doctype-public='-//W3C//DTD XHTML 1.0 Strict//EN'
12      doctype-system='http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
13  />
We see some directives for the XSLT processor. The output method should be html and should be indented.
The 'doctype-public' and 'doctype-system' attributes tell the XSLT engine to produce the proper heading for XHTML strict:

Code:
<DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Line 15-36 form the first template. It calls three templates as functions or subroutines.
  1. The template 'stylesheet' contains the CSS stylesheet to be used. Three style classes are defined: 'nr', 'text' and 'hr'.

    Code:
    47  <xsl:template name="stylesheet" > 
    48    .nr   { text-align: right; background-color: rgb(220,220,200); padding: .5em; }
    49    .text { text-align: left;  background-color: rgb(220,200,200); padding: .5em; }
    50    .hr   { text-align: right; background-color: silver ; padding: .5em; }
    51  </xsl:template>
  2. Template 'table-header' to generate the HTML tags for the the two table header rows.

    Code:
    53  <xsl:template name="table-header" > 
    54    <tr>
    55      <td class='hr' style="text-align: center" colspan='4' >I n t e r r u p t s</td>
    56    </tr>
    57    <tr>
    58      <td class='hr'>IRQ</td>
    59      <td class='hr'>Device</td>
    60      <td class='hr'>Total</td>
    61      <td class='hr'>Rate</td>
    62    </tr>
    63  </xsl:template>
  3. The 'total' template adds the 'total' and 'rate' attributes, from all the XML elements 'irq':

    Code:
      <irq nr='14' dev='pciide0' total="179284" rate="0" />
    Note that we don't use the grandtotals as reported by vmstat and stored in the ' <summary grandtotal='566212309' grate='232' />' element.
    Fixing this is left as an exercise for the reader.

    Code:
    65  <xsl:template name="total" > 
    66  <tr>
    67    <td class='hr' colspan='2' >T o t a l</td>
    68    <td class='hr'><xsl:value-of select='format-number(sum(//@total),"#,###")' /> </td>
    69    <td class='hr'><xsl:value-of select='format-number(sum(//@rate), "#,###")' /> </td>
    70  </tr>
    71  </xsl:template>

The template which matches the 'irq' element extracts the IRQ number, device name, interrupt total and rate from lines like '<irq nr='14' dev='pciide0' total="179284" rate="0" />'.

Code:
38  <xsl:template match="irq">
39  <tr>
40    <td class='nr'>   <xsl:value-of select="@nr"/>    </td>
41    <td class='text'> <xsl:value-of select="@dev"/>   </td>
42    <td class='nr'>   <xsl:value-of select="format-number(@total,'#,###')"/> </td>
43    <td class='nr'>   <xsl:value-of select="format-number(@rate,'#,###')" /> </td>
44  </tr>
45  </xsl:template>
After having seen all parts, we now will have a look at the main template which matches the root element 'vmstat-i'.

Code:
15  <xsl:template match="/vmstat-i" >
16    <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"  >
17      <head>
18        <title>vmstat -i</title>
19        <style type="text/css" >
20          <xsl:call-template name="stylesheet"/>
21        </style>
22      </head>
23      <body>
24        <table>
25          <xsl:call-template name="table-header" />
26          <xsl:apply-templates select="irq">
27            <!-- sort by IRQ number low to high -->
28            <xsl:sort select='@nr' data-type='number' order='ascending' /> 
29            <!-- with identical, shared IRQ, show highest total first -->
30            <xsl:sort select='@total' data-type='number' order='descending' /> 
31          </xsl:apply-templates> 
32          <xsl:call-template name="total" />
33        </table>
34      </body>
35    </html>
36  </xsl:template>
The opening 'html' tag, with the proper namespace declaration for XHTML strict, is created in line 16.

Lines 17-22 will produce the html 'head' tag. The CSS stylesheet is included by calling the named template 'stylesheet'.

The html 'body' element is created in lines 23-34. This consist of a single 'table' composed by lines 24-33.

After invoking the 'table-header' template, the XSLT engine is directed to execute the template matching 'irq' in line 26. The output of this template will be sorted by IRQ number in ascending order. In case of shared IRQ's, the one with the highest interrupts will be shown first.

After the calculation of the grand totals in line 32, the 'table', 'body', and 'html' tags are properly closed in the remaining lines 33-35.




1.6 Applying the XSL stylesheet in a browser

If a physical result file in HTML format is not needed, you can just load the 'vmstat-iz.xml' file into Firefox.
The 'href' attribute of <?xml-stylesheet href='vmstat-i.xsl' type='text/xsl' ?> is enough for Firefox to perform the XSLT transformation on the fly.

For the transformation inside a browser to work, the 'output method' really needs to to be html

Code:
<xsl:output
    method='html'
    omit-xml-declaration='no'
    indent='yes' 
    standalone='yes'
    doctype-public='-//W3C//DTD XHTML 1.0 Strict//EN'
    doctype-system='http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
/>
To prevent Internet Explorer from going into quirks mode, you should set omit-xml-declaration to no.

Point your browser to vmstat-iz.xml to find out whether your browser supports XSLT transformations on the fly,.

For a local test, you have to make sure that the XSL stylesheet is in the same directory. If for some reason you want the stylesheet in another location then you will have to hack line 5 of the 'vmstat2xml.sed' file to produce the correct 'href'.

If you expect to see the HTML code, by selecting the Firefox 'View page source" menu option, or by by pressing CTRL-U, you will be disappointed. All you will see is a a nicely coloured, version of the XML file.
For a physical transformation result you will have to use a stand-alone XSLT processor, as discussed in the following two sections.




1.7 Using Xalan-c for the XSLT transformation

Xalan comes in two flavours, one in C and one in Java. Both are available in FreeBSD ports as 'textproc/xalan-c-1.10.0' and 'textproc/xalan-j-2.7.0_2'.

Code:
xalan-c-1.10.0
    XSLT processor from the Apache XML Project
    Maintained by: ports@FreeBSD.org
    Requires: gettext-0.17_1, gmake-3.81_3, libiconv-1.11_1, xerces-c2-2.7.0

xalan-j-2.7.0_2
    Apache XSLT processor for transforming XML documents
    Maintained by: hq@FreeBSD.org
    Requires: apache-ant-1.7.0_2, diablo-jdk-1.6.0.07.02, inputproto-1.4.2.1,
    javavmwrapper-2.3.2, kbproto-1.0.3, libICE-1.0.4_1,1, libSM-1.0.3_1,1,
    libX11-1.1.3_1,1, libXau-1.0.3_2, libXdmcp-1.0.2_1, libXext-1.0.3,1,
    libXi-1.1.3,1, libXp-1.0.0,1, libXt-1.0.5_1, libXtst-1.0.3_1, pkg-config-0.23_1,
    printproto-1.0.3, recordproto-1.13.2, xerces-j-2.9.0_2, xextproto-7.0.2, xproto-7.0.10_1
    Also listed in: Java
Dr. XSLT uses OpenBSD, which doesn't have a port for Xalan-c.

The following Makefile deals with that by using 'scp' to copy the out of date dependencies to a FreeBSD box named 'plato', and to invoke 'Xalan' via 'ssh'.

Code:
# -- Makefile for applying XSLT stylesheets to XML sources using Xalan-c on a remote box 
# $Id: vmstat-makeover.xml,v 1.12 2008/09/12 04:00:10 j65nko Exp $

# -- source file definition in variable FILE and STYLESHEET 
# --     (without .xml and .xsl extension)

# The '?=' means, assign these values only if not already defined
# on the command line e.g. : $ make FILE=vmstat-makeover STYLESHEET=howto

FILE            ?=      vmstat-iz
STYLESHEET      ?=      vmstat-i

# ------------ end of source file definitions 

SOURCE          = ${FILE}.xml
RESULT_HTML     = ${FILE}.html

STYLESTEET_HTML = ${STYLESHEET}.xsl
STYLESHEET_XHTML= ${STYLESHEET}_XHTML.xsl
TEMP            = ${FILE}_temp.html

# --- dependencies

${RESULT_HTML}: ${TEMP}
	# -- remove empty 'xmlns' attributes which prevent validation by http://validator.w3.org/ 
	sed -e 's/xmlns=""//g' -e "s/xmlns=''//g" ${.ALLSRC} >${.TARGET}

# -- copy Out Of Date  dependencies to box plato, running FreeBSD and Xalan-c
# -- For some reason Xalan complains if there is no space between the
# -- '-i' (amount of indentation) and the number of indentation spaces

${TEMP}: ${SOURCE} ${STYLESHEET_XHTML}
	@echo TARGET ${.TARGET} has these  out of date dependencies: ${.OODATE}
	scp ${.OODATE} j65nko@plato:ARTICLES
	ssh j65nko@plato 'cd ARTICLES ; Xalan -i 2 ${.ALLSRC}' >${.TARGET}

# ---------------------------------------------------------------------------------------
# The html output method is required to have the XML file transformed inside a browser,
# This however does not produce valid XML. 
# See http://www.w3.org/TR/xslt#section-HTML-Output-Method

# For XHTML strict (HTML redefined into XML) we have to change the output method
# from 'html' to 'xml'.
# So it is convenient to standardize on html output, and only change to XML for producing
# XHTML by an external stand-alone XSLT engine/processor
 
${STYLESHEET_XHTML}: ${STYLESTEET_HTML} 
	@echo TARGET ${.TARGET} has these  out of date dependencies: ${.OODATE}
	# change output method to 'xml'
	sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" ${.ALLSRC} >${.TARGET}

# ---------------------------------------------------------------------------------------
#       sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" ${.ALLSRC} >${.TARGET}
# 
#  /<xsl:output/        : the line nr (address) with the start of the 'xsl:output' element
#  ,                    : separating first address of second address
#  /\/>/                : the line nr (address) of the closing '/>' of the 'xsl:output' element
#                       : we now have a line number range as the source for the search and replace:

#                               s/method='html'/method='xml'/
#                       
#       s               : search and replace command
#       /method='html'/ : search for the string 'method='html' 
#       /method='xml'/  : and replace with '/method='xml'
#
# ---------------------------------------------------------------------------------------

clean:
	rm ${STYLESHEET_XHTML} ${TEMP} ${RESULT_HTML}

show:
	ls -ltT
The actual command is: Xalan -i 2 vmstat-iz.xml vmstat-i.xsl >vmstat-iz.html.
Alternatively, you can use the '-o' option to specify the output file.

Code:
$ Xalan ?
Xalan version 1.8.0.
Xerces version 2.6.0.
Usage: Xalan [options] source stylesheet
Options:
  -a                    Use xml-stylesheet PI, not the 'stylesheet' argument
  -e encoding           Force the specified encoding for the output.
  -i integer            Indent the specified amount.
  -m                    Omit the META tag in HTML output.
  -o filename           Write output to the specified file.
  -p name expression    Sets a stylesheet parameter.
  -t                    Display timing information.
  -u                    Disable escaping of URLs in HTML output.
  -?                    Display this message.
  -v                    Validates source documents.
  -                     A dash as the 'source' argument reads from stdin.
                        ('-' cannot be used for both arguments.)
An example of the terminal output produced by this Makefile (some whitespace added for clarification):

Code:
$ make

TARGET vmstat-i_XHTML.xsl has these out of date dependencies: vmstat-i.xsl
# change output method to 'xml'
sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" vmstat-i.xsl >vmstat-i_XHTML.xsl

TARGET vmstat-iz_temp.html has these out of date dependencies: vmstat-iz.xml vmstat-i_XHTML
.xsl
scp vmstat-iz.xml vmstat-i_XHTML.xsl j65nko@plato:ARTICLES
vmstat-iz.xml                                            100%  870     0.9KB/s   00:00    
vmstat-i_XHTML.xsl                                       100% 2343     2.3KB/s   00:00    
ssh j65nko@plato 'cd ARTICLES ; Xalan -i 2 vmstat-iz.xml vmstat-i_XHTML.xsl' >vmstat-iz_temp.html

# -- remove empty 'xmlns' attributes which prevent validation by http://validator.w3.org/
sed -e 's/xmlns=""//g' -e "s/xmlns=''//g" vmstat-iz_temp.html >vmstat-iz.html
The generated XHTML by Xalan-c:

Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!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" lang="en" xml:lang="en">
  <head>
    <title>vmstat -i</title>
    <style type="text/css"> 
  .nr   { text-align: right; background-color: rgb(220,220,200); padding: .5em; }
  .text { text-align: left;  background-color: rgb(220,200,200); padding: .5em; }
  .hr   { text-align: right; background-color: silver ; padding: .5em; }
</style>
  </head>
  <body>
    <table>
      <tr >
        <td class="hr" style="text-align: center" colspan="4">I n t e r r u p t s</td>
      </tr>
      <tr >
        <td class="hr">IRQ</td>
        <td class="hr">Device</td>
        <td class="hr">Total</td>
        <td class="hr">Rate</td>
      </tr>
      <tr >
        <td class="nr">0</td>
        <td class="text">clock</td>
        <td class="nr">243,870,818</td>
        <td class="nr">99</td>
      </tr>

      [snipped]

      <tr >
        <td class="hr" colspan="2">T o t a l</td>
        <td class="hr">566,212,309</td>
        <td class="hr">230</td>
      </tr>
    </table>
  </body>
</html>




1.8 Using Sablotron for the XSLT transformation

Sablotron is available in the OpenBSD ports system.

Code:
Version: 1.0.1p3, Package name: sablotron-1.0.1p3
Maintained by: Anil Madhavapeddy
Required to run:
[converters/libiconv]
Required to build:
[devel/gmake] [devel/libtool] [textproc/p5-XML-Parser]
The FreeBSD port information:

Code:
Sablot-1.0.3
    XML toolkit implementing XSLT 1.0, XPath 1.0 and DOM Level2
    Maintained by: skv@FreeBSD.org
    Requires: expat-2.0.1, gettext-0.17_1, gmake-3.81_3, libiconv-1.11_1,
    libtool-1.5.26, p5-XML-Parser-2.36, perl-5.8.8_1
Invoke Sablotron with sabcmd vmstat-i.xsl vmstat-iz.xml >vmstat-iz.html.
Note that the order of the source files is different from 'Xalan' See sabcmd(1) for more information.

The 'Makefile' for Sablotron:

Code:
# -- Makefile for applying XSLT stylesheets to XML sources using Sablotron 
# -- $Id: vmstat-makeover.xml,v 1.12 2008/09/12 04:00:10 j65nko Exp $

# -- source file definition in variable FILE and STYLESHEET 
# --     (without .xml and .xsl extension)

# The '?=' means, assign these values only if not already defined
# on the command line e.g. : $ make FILE=vmstat-makeover STYLESHEET=howto

FILE            ?=      vmstat-iz
STYLESHEET      ?=      vmstat-i

# ------------ end of source file definitions 

SOURCE		= ${FILE}.xml
RESULT_HTML	= ${FILE}.html

STYLESTEET_HTML = ${STYLESHEET}.xsl
STYLESHEET_XHTML= ${STYLESHEET}_XHTML.xsl
TEMP		= ${FILE}_temp.html

# --- dependencies

${RESULT_HTML}: ${TEMP}
	# -- remove empty 'xmlns' attributes which prevent validation by http://validator.w3.org/ 
	sed -e 's/xmlns=""//g' -e "s/xmlns=''//g" ${.ALLSRC} >${.TARGET}

${TEMP}: ${STYLESHEET_XHTML} ${SOURCE} 
	@echo TARGET ${.TARGET} has these  out of date dependencies: ${.OODATE}
	sabcmd ${.ALLSRC} >${.TARGET}

# ---------------------------------------------------------------------------------------
# The html output method is required to have the XML file transformed inside a browser,
# This however does not produce valid XML. 
# See http://www.w3.org/TR/xslt#section-HTML-Output-Method

# For XHTML strict (HTML redefined into XML) we have to change the output method
# from 'html' to 'xml'.
# So it is convenient to standardize on html output, and only change to XML for producing
# XHTML by an external stand-alone XSLT engine/processor
 
${STYLESHEET_XHTML}: ${STYLESTEET_HTML} 
	@echo TARGET ${.TARGET} has these  out of date dependencies: ${.OODATE}
	# change output method to 'xml'
	sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" ${.ALLSRC} >${.TARGET}

# ---------------------------------------------------------------------------------------
#	sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" ${.ALLSRC} >${.TARGET}
# 
#  /<xsl:output/	: the line nr (address) with the start of the 'xsl:output' element
#  ,			: separating first address of second address
#  /\/>/		: the line nr (address) of the closing '/>' of the 'xsl:output' element
#			: we now have a line number range as the source for the search and replace:

#				s/method='html'/method='xml'/
#			
#	s		: search and replace command
#	/method='html'/	: search for the string 'method='html' 
#	/method='xml'/	: and replace with '/method='xml'
#
# ---------------------------------------------------------------------------------------

clean:
	rm ${STYLESHEET_XHTML} ${TEMP} ${RESULT_HTML}

show:
	ls -ltT
An invocation of the Makefile as example (some whitespace added for clarification):

Code:
$ make

TARGET vmstat-i_XHTML.xsl has these out of date dependencies: vmstat-i.xsl
# change output method to 'xml'
sed -e "/<xsl:output/,/\/>/s/method='html'/method='xml'/" vmstat-i.xsl >vmstat-i_XHTML.xsl

TARGET vmstat-iz_temp.html has these out of date dependencies: vmstat-i_XHTML.xsl vmstat-iz.xml
sabcmd vmstat-i_XHTML.xsl vmstat-iz.xml >vmstat-iz_temp.html
Warning [code:93] [URI:file:///home/j65nko/Makeover/Sablotron/vmstat-iz.xml] [line:20] 
  unsupported language 'en'
Warning [code:93] [URI:file:///home/j65nko/Makeover/Sablotron/vmstat-iz.xml] [line:20] 
  unsupported language 'en'

# -- remove empty 'xmlns' attributes which prevent validation by http://validator.w3.org/
sed -e 's/xmlns=""//g' -e "s/xmlns=''//g" vmstat-iz_temp.html >vmstat-iz.html
The result is the file 'vmstat-iz.html'.




1.9 Resources
  1. Wikipedia XML article
  2. Wikipedia XSLT article
  3. A Technical Introduction to XML by Norman Walsh
  4. Home page of Sablotron XSLT processor
  5. Home page of Xalan XSLT processor.




1.10 Epilogue

Dr. XML and Dr. XSLT have developed similar beautifying procedures for pfclt -sl and df -i output. They intend to report about these procedures in the following months.

$Id: vmstat-makeover.xml,v 1.12 2008/09/12 04:00:10 j65nko Exp $
$Id: vbul-html.xsl,v 1.14 2008/09/12 03:44:16 j65nko Exp $
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump

Last edited by J65nko; 1st December 2011 at 09:53 PM. Reason: silenceisdefeat.org ->silenceisdefeat.com
Reply With Quote
  #2   (View Single Post)  
Old 12th September 2008
J65nko J65nko is online now
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 3,263
Thanked 182 Times in 149 Posts
Default Download files and guide in HTML format

Attached is a *.tgz archive containing all files discussed in this guide. As a bonus the complete guide in HTML format, for easier scrollbar-less viewing, studying or printing.

Extract the files with
Code:
$ tar xvzf vmstat-makeover.tgz

Makeover
Makeover/Xalan
Makeover/Xalan/vmstat-iz.xml
Makeover/Xalan/Makefile
Makeover/Xalan/vmstat-i.xsl
Makeover/Sablotron
Makeover/Sablotron/Makefile
Makeover/Sablotron/vmstat-iz.xml
Makeover/Sablotron/vmstat-i.xsl
Makeover/vmstat-iz.xml
Makeover/vmstat2xml.sed
Makeover/vmstat-i.xsl
Makeover/vmstat.txt
Makeover/vmstat-makeover.html
The unpacking creates a directory 'Makeover' which contains the following files/links:
Code:
$ ls -lR Makeover/

total 120
drwxr-xr-x  2 j65nko  j65nko    512 Sep 11 04:54 Sablotron
drwxr-xr-x  2 j65nko  j65nko    512 Sep 11 04:53 Xalan
-rw-r--r--  1 j65nko  j65nko   2344 Sep  8 04:23 vmstat-i.xsl
-rw-r--r--  1 j65nko  j65nko    870 Sep 11 02:06 vmstat-iz.xml
-rw-r--r--  1 j65nko  j65nko  46603 Sep 12 06:31 vmstat-makeover.html
-rw-r--r--  1 j65nko  j65nko    705 Sep 11 04:55 vmstat.txt
-rwxr-xr-x  1 j65nko  j65nko    441 Sep 11 02:06 vmstat2xml.sed

Makeover/Sablotron:
total 8
-rw-r--r--  1 j65nko  j65nko  2587 Sep 11 02:10 Makefile
lrwxr-xr-x  1 j65nko  j65nko    15 Sep 11 02:19 vmstat-i.xsl -> ../vmstat-i.xsl
lrwxr-xr-x  1 j65nko  j65nko    16 Sep 11 02:14 vmstat-iz.xml -> ../vmstat-iz.xml

Makeover/Xalan:
total 8
-rw-r--r--  1 j65nko  j65nko  3058 Sep 11 02:15 Makefile
lrwxr-xr-x  1 j65nko  j65nko    15 Sep 11 02:20 vmstat-i.xsl -> ../vmstat-i.xsl
lrwxr-xr-x  1 j65nko  j65nko    16 Sep 11 02:14 vmstat-iz.xml -> ../vmstat-iz.xml
Attached Files
File Type: tgz vmstat-makeover.tgz (13.2 KB, 26 views)

Last edited by J65nko; 13th September 2008 at 09:44 PM. Reason: typo
Reply With Quote
Reply

Tags
make, makefile, regular expressions, sablotron, sed, vmstat, xalan, xhtml, xml, xslt

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
dwm status bar won't display apm output asemisldkfj General software and network 6 16th August 2009 11:07 PM
strange dmesg output gosha OpenBSD General 4 11th March 2009 01:10 PM
Digital sound output Zodox FreeBSD General 5 12th November 2008 02:21 PM
C and file input/output 18Googol2 Programming 3 20th August 2008 04:02 PM
strange security run output deadeyes FreeBSD Security 5 2nd July 2008 04:51 PM


All times are GMT. The time now is 04:33 AM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content copyright © 2007-2010, the authors
Daemon image copyright ©1988, Marshall Kirk McKusick