This is a note to memorialize some work that I did today, in one place so that I remember how to do it, but also such that it may be of use to others.

, as I was working on a thematic structure for the Motivation and Rationale for this project, I noticed that the <hgroup> HTML tag was missing from the Relax NG schema I had been using to do validation and autocomplete in Emacs. The original was something I had cribbed from some random website and was several years out of date from the current state of the HTML spec.

It turns out that the Relax NG version in question of the HTML spec is maintained by the people at, since the WHATWG itself does not publish one. It also turns out that there is a package on ELPA, but it is as old as the files I already have. The Git repository containing the schema is active, with changes (to the schema itself) as recent as a couple months. Since they appear to be tracking WHATWG, I can just update the repository from time to time. There are nevertheless some wrinkles with this plan.

The first wrinkle is that the schema is embedded in a much larger engine and Web app, which also happens to be Java (i.e., big). This put me on a path to go figure out how to check out just a subtree from Git, something I had wondered about for a while. Cue Stack Overflow. Admittedly, the answers weren't quite satisfying, but they ultimately led me to this:

mkdir $REPO
cd $REPO
git init
git remote add upstream
git sparse-checkout set schema/
git pull --depth=1 upstream main

That formulation creates a new repository and uses the sparse-checkout subcommand to isolate the schema subdirectory, and then pulls just the latest version of the files.

It didn't take me long to notice that a bunch of schema files were missing, and a quick search in the repository on GitHub helped determine that I needed to run the build script to generate them. As such, I had to add it on my side:

git sparse-checkout add build/
git pull --depth=1 upstream main

The build script itself was unfortunately not written to run its jobs piecewise, but I was at least able to run just the part I wanted, by cheating it like this:

JAVA_HOME=/dev/null PYTHONPATH=build python3 -c 'from build import buildSchemaDrivers; buildSchemaDrivers()'

Note the script refused to run without a JAVA_HOME environment variable even though it never used it, so I fed it a bogus one. This gave me the full suite of schemas I needed to plunk into nxml-mode.

With my markup validation and autocomplete up to date, I set about repairing the key binding that had mysteriously disappeared one day, and that I had been limping along without for years. This is to bind element/attribute completion to C-RET like it had been in a previous version of nxml-mode, but had since been moved to an awkward two-step C-c /.

What turned out to have happened was that at some point the command nxml-complete had been deprecated and rolled into the standard completion-at-point. Originally, the hook looked like this:

(add-hook 'nxml-mode-hook
          (lambda ()
            (when (and (boundp 'nxml-mode-map) (boundp 'nxml-complete))
              (define-key nxml-mode-map (kbd "<C-enter>") 'nxml-complete)
              (define-key nxml-mode-map (kbd "<C-return>") 'nxml-complete))))

I had, at some point, changed nxml-complete to completion-at-point, so now it read this:

(add-hook 'nxml-mode-hook
          (lambda ()
            (when (and (boundp 'nxml-mode-map) (boundp 'completion-at-point))
              (define-key nxml-mode-map (kbd "<C-enter>") 'completion-at-point)
              (define-key nxml-mode-map (kbd "<C-return>") 'completion-at-point))))

…but it still wasn't giving me my key bindings for some reason. The a-ha moment came when I eliminated the when conditional. Turns out you have to use fboundp rather than boundp when the symbol you're trying to test is a function. So, years of busted functionality because of a single-character typo.