Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


Tip of the Day
Home » Tip Bank » XML » XSLT
Language: Web
Expertise: Advanced
Mar 2, 2000

Add a Counter to Your Web Page With XHTML

Browsers Targeted: Internet Explorer 3+, Netscape Navigator 3+

You can take advantage of the new XHTML standard in your own code, regardless of your browser, to enhance the capabilities of your Web pages. For example, page counters are common Web elements—so common that it would seem natural to express them as a tag. Because this information is server side, that tag expression would need to be interpreted on the server and replaced with the appropriate data. For example, suppose that you had an XHTML document such as visitors.htm:

 
<html xmlns:utils="http://www.vbxml.com/utils">
<body>
<h1>Visitors</h1>
<p>There have been <utils:pagecounter
style="font-size:14pt;color:blue;font-family:Impact;"/>
visitors to this site.</p>
</body>
</html>

You could then use an XSL filter (processUtils.xsl) to automatically handle any utils: tag within the source document. This uses the newer MSXML Preview parser to parse the XSL:

 
<!-- processUtils.XSL -->
<xsl:stylesheet version="1.0"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:msxsl="urn:schemas.microsoft.com:xslt"
                xmlns:utils="http://www.vbxml.com/utils"
            xmlns:vis="http://www.vbxml.com/visitors"
            >
<xsl:output method="xml"/>
<xsl:param name="counterSource">
<counter name="visitors.xml" visitors="34"/></xsl:param>
<xsl:param name="pageName" select="'default.htm'"/>

<xsl:template match="/">
   <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="*|@*|text()">
   <xsl:copy><xsl:apply-templates select="*|@*|text()"/></xsl:copy>
</xsl:template>

<xsl:template match="utils:pagecounter">
   <span>
   <xsl:for-each select="@*">
        <xsl:attribute name="{name()}"><xsl:value-of/></xsl:attribute>
    </xsl:for-each>
   <xsl:value-of select="vis:updateVisitors($counterSource,$pageName)"/>
   </span>
</xsl:template>
</xsl:stylesheet>

Additionally, you need two other files, an XML document to contain the counter (counter.xml):

 
<counters>
</counters>

and an ASP file to retrieve the file to be processed and produce the appropriate output, using an XSL processor:

 
<%
'response.expires=-1
'processUtils.asp
file=request("file")

class CVisitors
   function updateVisitors(nodeList,pageName)
      set nodeDoc=nodeList.item(0)
      set node=nodeDoc.documentElement.selectSingleNode _
      ("//counter[@name='"+pageName+"']")
      if node is nothing then
          set node=nodeDoc.documentElement.appendChild _
          (nodeDoc.createElement("counter"))
            node.setAttribute "name",pageName
         node.setAttribute "visitors",0
      end if
      visitorCt=clng(node.getAttribute("visitors"))
      node.setAttribute "visitors",cstr(visitorCt+1)
       updateVisitors=node.getAttribute("visitors")
   end function
end class


if not isObject(utils) then
   set utilsDoc=createObject("MSXML2.FreeThreadedDOMDocument")
   set template=createObject("MSXML2.XSLTemplate")
   utilsDoc.load server.mapPath("processUtils.xsl")
   set template.stylesheet=utilsDoc
   set utils=template.createProcessor
   set session("utils")=utils
   utils.output=response
   set visitors=new CVisitors
   utils.addObject Visitors,"http://www.vbxml.com/visitors"
else
   set utils=session("utils")
end if

set xmlDoc=createObject("MSXML2.FreeThreadedDOMDocument")
xmlDoc.load server.mapPath(file)
utils.input=xmlDoc
set counterDoc=createObject("MSXML2.FreeThreadedDOMDocument")
counterDoc.load server.mapPath("counters.xml")
utils.addParameter "counterSource",counterDoc
utils.addParameter "pageName",file
utils.transform 
counterDoc.save server.mapPath("counters.xml")
%>

Note in this particular case that the utils object has two parameters—the counterSource (which indicates the location of the counter.xml file) and the pageName (which uses the name of the file to act as a key to identify the proper <counter> element). It also incorporates an object from the CVisitor class, which updates the appropriate counter within the XSL script. Note that the object only needs to be associated with the XSL processor once.

Finally, this would be called from a command line by passing the filename of the XHTML file you want to transform as a query string argument to the processUtils.asp file—for example, http://www.vbxml.com/processUtils.asp?file=default.htm. Through this mechanism, you've created an alternative processing technique for files that uses ASP only to do the initialization and uses XML and XSL for everything else (the processUtils.xsl file takes on the role of ASP in its normal guise of creating fine-grained output).

This may seem like a lot of work for transforming one element (you could do this just as readily with a straight script) but if you had a number of utils: elements where each had its own associated mapping within the processUtils.xsl file, then the advantage rapidly shifts to the XML architecture.

Kurt Cagle
 
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap