Via the Lotus Domino Support RSS feed: How to access .Net classes from LotusScript.
Apply XSLT style sheet to an XML document for browser friendly display
As posted posted previously I’m doing quite a lot of work with XML these days. As part of the process I’m writing XSLT style sheets to make sure the XML documents displays nicely in the browser if the user decides to open the XML document directly in the browser. Doing so is surprisingly simple.
A practical example of linking a style sheet to an XML document is used in many RSS/ATOM feeds to let the user know what is they opened and how they should really handle the feed.
Suppose you have a XML document describing a traceroute as shown below. What you really want is for the user to see a HTML table summarizing the traceroute command in the browser instead of the barebones DOM tree. To do so you only need to add a <?xml-stylesheet /> tag at the top of the XML document with the URL to a XSLT style sheet.
Below you can see an example of an XML document with an embedded <?xml-stylesheet /> tag, the XSLT style sheet and the HTML table that results from the transformation.
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="traceroute.xsl" type="text/xsl"?>
<traceRoute target="yahoo.com" hostAddress="66.94.234.13"
hostName="w2.rc.vip.scd.yahoo.com" initiated="2006-05-17T09:46:18.378"
completed="2006-05-17T09:46:25.668">
<hop hopNumber="1" hostAddress="192.168.1.1"
hostName="192.168.1.1">
<timing responseReceived="true" roundTripTime="2" />
<timing responseReceived="true" roundTripTime="1" />
<timing responseReceived="true" roundTripTime="1" />
</hop>
<hop hopNumber="2" hostAddress="80.243.112.1"
hostName="1.112.243.80.vl20-cph.dhcp.clearwire.dk">
<timing responseReceived="true" roundTripTime="28" />
<timing responseReceived="true" roundTripTime="67" />
<timing responseReceived="true" roundTripTime="33" />
</hop>
<hop hopNumber="3" hostAddress="208.49.181.237"
hostName="ge-1-1-0.400.br1.CPH1.gblx.net">
<timing responseReceived="true" roundTripTime="37" />
<timing responseReceived="true" roundTripTime="58" />
<timing responseReceived="true" roundTripTime="39" />
</hop>
<hop hopNumber="4" hostAddress="67.17.64.69"
hostName="so7-2-0-2488M.ar1.DCA3.gblx.net">
<timing responseReceived="true" roundTripTime="220" />
<timing responseReceived="true" roundTripTime="156" />
<timing responseReceived="true" roundTripTime="117" />
</hop>
<hop hopNumber="5" hostAddress="208.51.74.182"
hostName="yahoo-2.ar1.DCA3.gblx.net">
<timing responseReceived="true" roundTripTime="115" />
<timing responseReceived="true" roundTripTime="121" />
<timing responseReceived="true" roundTripTime="142" />
</hop>
<hop hopNumber="6" hostAddress="216.115.101.130"
hostName="so-3-1-0.pat2.pao.yahoo.com">
<timing responseReceived="true" roundTripTime="234" />
<timing responseReceived="true" roundTripTime="193" />
<timing responseReceived="true" roundTripTime="195" />
</hop>
<hop hopNumber="7" hostAddress="216.115.106.181"
hostName="ge-3-0-0-p250.msr2.scd.yahoo.com">
<timing responseReceived="true" roundTripTime="189" />
<timing responseReceived="true" roundTripTime="185" />
<timing responseReceived="true" roundTripTime="187" />
</hop>
<hop hopNumber="8" hostAddress="66.218.82.219"
hostName="ten-1-3-bas2.scd.yahoo.com">
<timing responseReceived="true" roundTripTime="210" />
<timing responseReceived="true" roundTripTime="206" />
<timing responseReceived="true" roundTripTime="201" />
</hop>
<hop hopNumber="9" hostAddress="66.94.234.13"
hostName="w2.rc.vip.scd.yahoo.com">
<timing responseReceived="true" roundTripTime="186" />
<timing responseReceived="true" roundTripTime="184" />
<timing responseReceived="true" roundTripTime="210" />
</hop>
</traceRoute>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output method="html" version="1.1" encoding="iso-8859-1" />
<xsl:template match="/traceRoute">
<html>
<body>
<table border="1">
<xsl:for-each select="//hop">
<tr>
<td>
<xsl:value-of select="@hopNumber" />
</td>
<td>
<xsl:value-of select="@hostAddress" />
</td>
<td>
<xsl:value-of select="@hostName" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
| 1 | 192.168.1.1 | 192.168.1.1 |
| 2 | 80.243.112.1 | 1.112.243.80.vl20-cph.dhcp.clearwire.dk |
| 3 | 208.49.181.237 | ge-1-1-0.400.br1.CPH1.gblx.net |
| 4 | 67.17.64.69 | so7-2-0-2488M.ar1.DCA3.gblx.net |
| 5 | 208.51.74.182 | yahoo-2.ar1.DCA3.gblx.net |
| 6 | 216.115.101.130 | so-3-1-0.pat2.pao.yahoo.com |
| 7 | 216.115.106.181 | ge-3-0-0-p250.msr2.scd.yahoo.com |
| 8 | 66.218.82.219 | ten-1-3-bas2.scd.yahoo.com |
| 9 | 66.94.234.13 | w2.rc.vip.scd.yahoo.com |
Rediscovering a lost gem – Stopwatch
Got a call from a customer reporting that the news on frontpage on their intranet was appearing very slowly. The news are displayed using an AJAX approach for asynchroneous loading using an agent as the data source for the XML. So far I haven’t been aware of any performance problems but “suddenly” the functionality is performing very poorly. Time to debug.
While pondering how to troubleshoot the performance problems I remembered the Stopwatch LotusScript class. I have used the class previously in other projects and it works like a charm. The class is originally from a THE VIEW article called “Performance Testing LotusScript Code Using Object-Oriented Design Techniques” by Burke LaShell (January/February 2000).
Using the class is a simple as these steps:
- Download the stopwatchclass.nsf database from the article abstract page.
- Copy the Stopwatch script library from the database to the database you would like to use it in.
- Use the Stopwatch class using its very simple API.
- After each run the class will produce a nice looking e-mail report.
Below is an example of using the class. The code should be self-explainatory but notice the use of the Stopwatch class and its Start and Stop methods.
Sub Initialize 'declarations Dim session As New NotesSession Dim docContext As NotesDocument Dim subsite As String Dim fetcher As NewsFetcher Dim xml_conv As XmlConverter Dim repositories As Vector Dim xml As String Dim query_string As String 'create stopwatch Dim stopwatch As New Stopwatch 'error On Error Goto catch 'get document context Set docContext = session.DocumentContext 'get QueryString query_string = docContext.QUERY_STRING(0) 'get the requested sub-site key if any (i.e. sdainfo, scaninfo) subsite = Strrightback(query_string, "&subsite=") 'create a NewsFetcher Call stopwatch.Start(|New NewsFetcher|) Set fetcher = New NewsFetcher(subsite) Call stopwatch.Stop(|New NewsFetcher|) 'create a XMLConverter Call stopwatch.Start(|New XmlConverter|) Set xml_conv = New XmlConverter() Call stopwatch.Stop(|New XmlConverter|) 'get the news documents Call stopwatch.Start(|fetcher.GetRepositories()|) Set repositories = fetcher.GetRepositories() Call stopwatch.Stop(|fetcher.GetRepositories()|) 'convert the documents to XML Call stopwatch.Start(|xml_conv.Convert()|) xml = xml_conv.Convert(repositories) Call stopwatch.Stop(|xml_conv.Convert()|) 'write the XML back to the browser Call stopwatch.Start(|Print XML|) Print "Content-type: text/xml" Print xml Call stopwatch.Stop(|Print XML|) 'exit Goto finally catch: Print Error & ", line: " & Erl Resume finally finally: 'send Call stopwatch.MailAllWatchValues(|jdoe@example.com|, |Agent Debug - "(WEB - NewsFeed)"|) 'exit Exit Sub End Sub
The above code will produced a report like the one shown below for each run (the report is e-mailed to jdoe@example.com). As you can see the total run time was 8,8 seconds (!!!) with the fetcher.GetRepositories() call taking up all of the time.
seconds % calls secs/call event =========================================================================== 00008,812 100,0% 0000001 00008,812 Total run time 00008,812 100,0% 0000001 00008,812 fetcher.GetRepositories() 00008,812 100,0% 0000001 00008,812 NotesRepo.GetDocs() - get news docs 00000,000 000,0% 0000001 00000,000 New NewsFetcher 00000,000 000,0% 0000001 00000,000 New XmlConverter 00000,000 000,0% 0000001 00000,000 NotesRepo.GetDocs() - get view 00000,000 000,0% 0000001 00000,000 xml_conv.Convert() 00000,000 000,0% 0000001 00000,000 Print XML
Using this data I was able to diagnose and solve the problem. Below is performance data from the agent after solving the problem (a view index refresh problem) – notice how the runtime is now a mere 0,015 seconds…
seconds % calls secs/call event =========================================================================== 00000,015 100,0% 0000001 00000,015 Total run time 00000,015 100,0% 0000001 00000,015 xml_conv.Convert() 00000,000 000,0% 0000001 00000,000 New NewsFetcher 00000,000 000,0% 0000001 00000,000 New XmlConverter 00000,000 000,0% 0000001 00000,000 fetcher.GetRepo() 00000,000 000,0% 0000001 00000,000 NotesRepo.GetDocs() - get view 00000,000 000,0% 0000001 00000,000 NotesRepo.GetDocs() - get first document 00000,000 000,0% 0000001 00000,000 NotesRepo.GetDocs() - loop documents 00000,000 000,0% 0000001 00000,000 Print XML
There are two caveats to using the Stopwatch class:
- The agent has to allow restricted operations since the script library uses a function from kernel32.dll.
- Since the class uses kernel32.dll the script library only works on Windows.
Additional links for XML entity references
Just thought I would share a couple of links on XML entity references:
- developerWorks – Tip: Simplify with entity references
- ENTITY declaration
- Entities and XSLT
What’s new in Eclipse 3.2
Nice combined overview of what’s new in the upcoming release 3.2 of the Eclipse IDE at The EclipseZone.
Firefox and external XML entity references
I’m currently doing some work with XML and representing it as HTML in browsers using XSLT by including a reference to a style sheet. To reduce dublicating too much information across the different XML files I produce and use external entity references.
For those that doesn’t know what an external entity reference is let me give a short explanation. Bascially XML allows you to define an entity using the DOCTYPE declaration that may be referenced from within the XML document. A reference to an XML fragment as an entity may be internal (in the document itself) or external (in another file). The below code snippet shows how to reference an external file as an entity:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE file_contents [ <!ENTITY external_info SYSTEM "external_info.xml"> <!ENTITY internal_info "Some internal information"> ]> <file_contents> &external_info; &internal_info; </file_contents>
In the above example the &external_info; will be replaced with the contents of the external_info.xml file and &internal_info; will be replaced with “Some internal information” when the file is parsed.
I found one limitation though when using external entity references in that Firefox doesn’t include XML from these external references in the source document for the XSLT transformation (or when previewing the document). This isn’t an issue in Internet Explorer at all so for this particular project it’s nice that the users are on Internet Explorer.
After researching the issue on Google I found an article on developerWorks (XML in Firefox 1.5, Part 2: Basic XML processing) that confirms my findings:
"As far as reading external files, Firefox does not read any external entities at all, whether parameter entities (such as DTDs and DTD fragments) or general entities (external, well-formed XML fragments). <snip /> Support of such external entities does have possible security implications, and possible performance implications, but both have workarounds, and I hope Firefox addresses these limitations soon."
I’m using Firefox 1.5.0.3 on Windows XP Prof. SP2.
Re: Firefox problem with multiple startup pages
As previously posted I had a problems with having multiple startup pages when running with the Tab Mix Plus extension in Firefox. I posted the issue in the extension forum and the issue was fixed in the dev. build. See the message in the forum for a link to the dev. build if you’re interested.
Notes/Domino 6 and 7 Forum: Java Thread Synchronization in HTTP JVM
Saw a very interesting post on Java thread synchronization in the Notes/Domino 6 and 7 Forum over at Lotus developerWorks. I see that Julian already posted a reply but he also admits he’s not exactly a subject matter expert. Anyone else who has some information on the subject that they dare to share?
Link to post: Java Thread Synchronization in HTTP JVM
Firefox problem with multiple startup pages
Don’t know if you are aware of this but in Firefox you can open multiple tabs automatically when the browser starts – kind of like homepage on steoroids. You do this by separating the URLs with the pipe character (|) in the list of homepages in the options (on the General tab in ToolsOptions…). I use this a lot if I found some information I do not care bookmarking but I’ll need the next day.
There seems to be a problem with this feature however. When reopening the browser the tabs will not expand and show the page titles (see screenshot below) until I close one tab. After researching a bit it turned out to be caused by the otherwise excellent Tab Mix Plus extension. Disabling the extension removes the issue. Hmm….
The issue is on Firefox 1.5.0.3 and Tab Mix Plus 0.3.0.5 on Windows XP SP2.
Don’t plan!!
Received a nice quote by John Preston of Boston University from my big brother:
“The nicest thing about not planning is that failure comes as a complete surprise and not preceded by a period of worry and depression.”