The first release of SDOM as been... released! Check it out at http://www.nongnu.org/sdom/. I've already found several major bugs since releasing, so it's obviously not ready for serious use, but it's very full-featured as it stands, and I'd be much obliged if people would take a look. (Currently it only works with Guile; hopefully some day there will be ports to PLT and Chicken, neither of which I know anything about.)
Here's an interesting little thing that came up, Scheme-wise, while I was working on SDOM. Backstory: A lot of the node-manipulation functions defined in the Core module will cause events to be dispatched; the Events module, though, which contains the event-handling functions, is optional. I wanted to make it so that an event dispatch would be fully handled if the Events module was loaded, a no-op otherwise. Here's the code I was using initially:
(if (defined? 'sdom:dispatch-event-internal)
(apply sdom:dispatch-event-internal args)
#f)
That wasn't working: Guile kept telling me it didn't know anything about sdom:dispatch-event-internal, and, infuriatingly, when I debugged it, I discovered that defined? was returning #t! I thought I was going nuts.
Here's the denouement, thanks in no small part to unknown_lamer in #guile: Apparently, defined? looks at the top-level environment, where exported module symbols go when you load a module. However, the environment in which my code was then trying to look up that function to apply it didn't contain that binding. After some trying, I found a way to do what I want:
(if (defined? 'sdom:dispatch-event-internal)
(apply (module-ref (resolve-module '(sdom events))
'sdom:dispatch-event-internal) args)
#f)
Phew!