More wiki

Ah yes, my “train project”… well, I have become somewhat disheartened twiddling around in BeeWiki, and may have to knock it on the head. The database has some nice pages and functionality, but one potential show-stopper — which initially I thought I could overcome — has kicked me in the nadgers:

The key issue with BeeWiki is that it uses a Java agent to render its content. This agent in turn uses the gnu.regexp package (java.util.regexp comes with J2SE 1.4.x so no joy there for Notes 5 / 6), and as a result, any code using said package is classed as Java that needs signing by an ID capable of running unrestricted agents. This makes it impractical for most Domino shops, even though regexp processing is a pretty benign activity. I tell you, it’s at times like this I find myself going off Domino…!

Anyway, back to wiki-style regexp processing. I have cobbled together a load of Javascript, invoked via onLoad(), which renders wiki markup to HTML. So far my fledgeling Javascript can do the following:

  • Convert text tagged ~some text~ to <em>some text</em>
  • Convert text tagged #some text# to <strong>some text</strong>
  • Convert text tagged _some text_ to an <h3> header
  • Convert URLs into links
  • Convert so-called WikiText (i.e. two or more proper case words mashed-together) to links
  • Wrap text tagged *some text thus: <li>some text</li> tags

The more problematic element of all this is converting line feed and carriage return characters to paragraph tags in the appropriate places, especially when combined with my list tag. Ho hum, I may soldier on for a bit more with that — or p’raps implement it all in @formula!

One of the pieces of code I’m more proud of is a computed (using @formula) Javascript onLoad() event in a $$ReturnGeneralError form, to intercept clicks on WikiLinks which haven’t yet been created.

What do I mean by that? Well, in a wiki, WikiLinks get created automagically, but there aren’t necessarily underlying pages for those links at the time of their creation. The wiki deals with this by making the link either an actual link to the page, or a link to create said page. For on-the-fly rendering in Domino (without Java) this is a little tricky, because working with WikiLinks means that a URL fragment like this:


gives a 404 if that page hasn’t yet been created. So, my Javascript routine intercepts this, and changes the window.location to something like this:


It works really well, although there is of course one caveat: ideally the system shouldn’t try to re-direct to a page creation URL like this when the 404 error generated is for something entirely unrelated!

Crikey, this post is rambling stream of consciousness. I doubt it’s even remotely useful. Oh well. I will be posting the relevant code snippets somewhere on this site soon. In fact, I have quite a few things to post here — my LinkedArray and FormValidator classes, plus an article I wrote for the soon-to-be-gone e-Pro Magazine for example. Sigh. A wee wiki would be perfect for all of that… Bah!

I guess the next train project is a regular expression class for Lotusscript… or has someone already done it? LOL!

Further reading: Mike Golding: Processing HTML using Regular Expressions.


  1. gnu regexp is very slow now… is there any way you could use ORO Matcher classes, I think Apache have them now as part of commons-everything…..
    Jason Bell#
  2. Hi Jason. Interesting, will take a look, thanks.

    In the meantime, because of the security restriction with Java in Domino, I have switched the rendering engine to one based upon Jen-Christian Fischer’s ( NotesWiki.

    Wiki markup conversion in Lotusscript?!? Yes, it really is possible, and not bad on the performance front either, which surprised me. In fact, the template is shaping up quite nicely, and I’ll release it soon.Ben Poole#
  3. I found the same problem when trying to use the updated Apache XMLRPC libraries for a new version of the XML-RPC interface for ddcTagTemplate, DomBlog, BlogSphere, etc.. The old XMLRPC libraries work fine but the new version requires that the agent is signed with an ID capable of running unrestricted agents. aargh!
    I decided to use the old version.

    The ORO Matcher is the way to go. After testing I found it was quicker of free regular expression libraries so I decided to use it as the basis for my own tag templating system for Domino.

    I adore regular expressions and use the following for testing them:

    "The Regulator"

    It integrates with a web service at which is a reasonable source of regular expression examples some need a little tweaking though.

    Ben, what do you mean by "train project" ?

    John Marshall#
  4. Thanks for the links John: up until now my exposure to regexp has been “little and often” - this wiki project has seen a lot more regexp coding, both in Java and Javascript, so that’s good (in my book). During my R&D, I tinkered with expressions at this site, which is quite a useful resource:

    Now then, “train project”: my job involves a 45 minute commute into London, so occasionally I code on the train in lieu of reading a book or sleeping :-) Ben Poole#
  5. I was just going to say "I did this already" but then I saw your comment #2 above ;-)

    Recently (as part of the ZAPPATA Personal Groupware project), I have coded a Textile parser / renderer in Java. Even with the power of RegExps, it *is* difficult to decide where to put the break and the paragraph tags.

    ZTextile (as we call it) may be released unter the LGPL … If we find time to clean it up etc…Jens-Christian Fischer#
  6. This script implements a LotusScript class (followed by a test routine) to provide powerful regular expression capabilities by using a VBScript RegExp object. Information about the Visual Basic Scripting RegExp object --

    Option Public
    Option Explicit

    Class RegExp

    ''' RegExp -- use VBScript RegExp object to provide regular expressions
    ' 2004-06-03 David Phillips, First version.

    Public matches As Variant
    Public oRegExp As Variant

    ' VBScript RegExp properties
    Public Pattern As String
    Public IgnoreCase As Boolean ' default = False
    Public Global As Boolean ' default = False

    Sub new ()
    Set oRegExp = CreateObject ("VBScript.RegExp")
    End Sub

    Public Function Match (source As String, pattern As String, matches As Variant) As Boolean
    ' RegEx.Match -- scan source for pattern, set matches collection and return true if any
    ' (Can't call it Execute as that collides with LotusScript built-in function and statement.)
    With oRegExp
    .Pattern = pattern ' regular expression to match
    .IgnoreCase = IgnoreCase
    .Global = Global
    Set matches = .Execute (source) ' do match
    Match = (Not 0 = matches.count)
    End With
    End Function

    Public Function Replaces (source As String, pattern As String, replacement As String) As String
    ' RegEx.Replaces -- scan source for pattern, if found substitute replacement, return result
    ' (Can't call it Replace as that collides with LotusScript built-in function.)
    With oRegExp
    .Pattern = pattern
    .IgnoreCase = IgnoreCase
    .Global = Global
    Replaces = .Replace (source, replacement) ' do replace
    End With
    End Function

    Public Function Test (source As String, pattern As String) As Boolean
    ' RegEx.Test -- scan source for pattern, return true if found
    With oRegExp
    .Pattern = pattern
    .IgnoreCase = IgnoreCase
    Test = .Test (source)
    End With
    End Function

    End Class

    Sub test_RegExp

    ' Include Use "RegExp" in Options section to refer to an external script library.

    Dim re As New RegExp

    ' Pattern matching defaults to case sensitive.
    Dim test As Boolean
    test = re.Test ("ABC", "b")
    msgbox "'ABC' contains 'b' (case sensitive) = " & test
    re.IgnoreCase = True
    test = re.Test ("ABC", "b")
    msgbox "'ABC' contains 'b' (case insensitive) = " & test

    ' Match returns success indication.
    test = re.Match ("xyz", "a")
    msgbox "'xyz' has a match for 'a' = " & test

    ' Global defaults to False; = return first match only.
    Dim count As Integer
    test = re.Match ("them these theirs", "e")
    ' Match returns successful matches as a collection property.
    count = re.matches.count
    msgbox "'them these theirs' with Global = false matches 'e' " & count & " time."

    re.Global = True
    test = re.Match ("them these theirs", "the[a-z]+")
    Dim position As Integer
    Dim length As Integer
    Dim s As String
    dim msg as string
    Forall m In re.matches
    position = m.FirstIndex ' zero-based
    length = m.Length
    s = m.Value
    msg = msg & "Match at position " & position & ". " & length & " character string = " & s & chr (10)
    End Forall
    msgbox msg

    ' Replaces returns source string with any successful replacement.
    s = re.Replaces (s1, "([a-z]*)\W(\w*)\s(\S*)", "$3 $2 $1")
    msgbox "Change 'them these theirs' to '" & s & "'."

    End Sub

    Keywords: RegEx, regular expression, Perl, PCRE (Perl Compatible Regular Expression), POSIX 1002.3, VBScript, LotusScript.David Phillips#

Comments on this post are now closed.


I’m a software architect / developer / general IT wrangler specialising in web, mobile web and middleware using things like node.js, Java, C#, PHP, HTML5 and more.

Best described as a simpleton, but kindly. You can read more here.