Editing XML schemas on Emacs with nXML

While looking into DocBook recently, I discovered that GNU emacs finally has a high-quality XML editing mode that includes validation of the documents. nXML mode is integrated into emacs23, and it comes with RELAX NG grammars to support docbook editing, though only for DocBook 4.2.

For work on PyXB, though, I really need something that handles XML Schema Definition (XSD) documents. emacs nXML doesn’t come with XSD support, but the RELAX NG homepage points to Jeni Tennison’s schema as a candidate.

This is a great start, but when I tried using it with xmllint from libxml2 to validate some schemas supported by PyXB it said they were invalid. There are a variety of subtle issues the original version didn’t quite get right (and a few cases where my example schema were wrong). I’ve updated the schema to fix those issues, and made it available on github.

emacs nXML comes with an XSLT RELAX NG schema, but only for version 1.0. As XSLT 3 is nearly complete at the time I’m writing this, I was hoping to find support to validate against other XSLT versions as well. Turns out Norman Walsh has provided a unified solution for XSLT 1.0, 2.0, and 3.0 on github.

So: To support XSD and XSLT editing with nXML in Emacs 23, I put this in my .emacs file:

;; nXML mode customization
(add-to-list 'auto-mode-alist '("\\.xsd\\'" . xml-mode))
(add-to-list 'auto-mode-alist '("\\.xslt\\'" . xml-mode))
(add-hook 'nxml-mode-hook
	  '(lambda ()
	     (make-local-variable 'indent-tabs-mode)
	     (setq indent-tabs-mode nil)
	     (add-to-list 'rng-schema-locating-files

I copied the original schema from the rng4xsd and xslt-relax-ng repositories, and used Trang to convert from the standard RELAX NG XML syntax to the compact syntax used by nXML. Then the following goes into ~/.emacs.d/nxml-schemas/schemas.xml:

<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
  <!-- Extend to support W3C XML Schema Definition Language, which as
       of 1.1 are known as "XSD" rather than "XML Schema" to avoid
       confusion with other XML schema languages such as RelaxNG. -->
  <uri pattern="*.xsd" typeId="XSD"/>
  <namespace ns="http://www.w3.org/2001/XMLSchema" typeId="XSD"/>
  <documentElement localName="schema" typeId="XSD"/>
  <typeId id="XSD 1.0" uri="xsd10.rnc"/>
  <typeId id="XSD" typeId="XSD 1.0"/>

  <!-- Extend to support all three XSLT variants.  These are all in
       the same namespace, but are distinguished by a version
       attribute in the document element.  If unqualified, a catch-all
       version is used. -->
  <uri pattern="*.xsl" typeId="XSLT"/>
  <uri pattern="*.xslt" typeId="XSLT"/>
  <namespace ns="http://www.w3.org/1999/XSL/Transform" typeId="XSLT"/>
  <typeId id="XSLT 1.0" uri="xslt10.rnc"/>
  <typeId id="XSLT 2.0" uri="xslt20.rnc"/>
  <typeId id="XSLT 3.0" uri="xslt30.rnc"/>
  <typeId id="XSLT" uri="xslt.rnc"/>

Now when I write my XSD schemas in emacs, the mode line tells me when they’re invalid, and I can use C-c C-n to jump to the error, with the explanation placed in the message line. Very nice.

Leave a Reply

Your email address will not be published. Required fields are marked *