SGMLtools Editor Whitepaper
PrevSGMLtools Editor WhitepaperNext

Basic Editing

The functionality that you can expect from any SGML editor is what I call "basic editing": parsing an SGML document, rendering it in a editable GUI component and letting the user modify the document by interacting with the GUI, and saving back the SGML document. This is the basic stuff that's needed and that must be implemented and working before work on more esoteric features (see below) can start.

SGML Input/Output

For the scope of this paper, we'll take SGML output for granted: once you have a SGML-compatible document object model in core, it is a reasonably simple task to traverse the data structures and spit out SGML.

Parsing SGML and storing it in an internal format that is compatible with the many uses the software wants to make from it is much more interesting. Two things need to be defined in this area:

  1. An SGML parser

  2. A Document Object Model

The two are related, but can be defined and implemented separately. Of course, the Document Object Model, which is the result of the parse phase, drives a lot of the SGML parser definition. Therefore, we start out with the DOM.

Document Object Model

An SGML document is typically stored in-core as a "grove", a "collection of trees and other things". The Document Model describes how this stuff is stored in memory and how other UI elements (in SmallSpeak, the Views and the Controllers) can interact with the Model. The Model therefore needs to implement five interfaces:

  1. A query interface, so that selected parts of the Model may be read by other actors in the system; this is used by the View to read out parts of the tree in order to render them;

  2. A modification interface, so that the controller can modify the tree without having to know about its internals;

  3. An extension interface, so that the Model may be asked for a list of possible children, attribute values, etcetera (for this, the Model likely talks to the DTD);

  4. A validation interface, so that the Model may be asked whether a certain value is allowed at a certain point. I'm not quite sure that a separate interface is beneficial (or that just attempting to modify and waiting for an exception to happen is fine, too), so it's listed here mainly for completeness.

  5. A mapping interface, so that a function can be handed to the model that is called for every element in the model; this can be used for SGML export, for example.

Internally, the Model contains objects down to the lowest (character entity) level. There are design patterns for dealing with this without having to fear for an explosion of objects, and it provides the cleanest and most straightforward way of implementing communication between the various components. Again, performance issues will be dealt with later, if necessary.

DTD compilation

For an editor to understand an SGML document, it needs to understand the structure of the document. The Document Type Definition needs to be made available to the SGML parser in a form that drives the SGML parser and lets it decide whether constructs are valid or not. This step can be quite tricky, because you're using a data structure on disk (the DTD) to generate another data structure (the parsed DTD) that modifies the behaviour of a complicated piece of code (the SGML parser).

I think that a lot of this complexity can be taken away by splitting the SGML parser in a syntax analyzing front-end (which, for the first version, can be hardwired to recognize the extended reference concrete syntax we want to support), which drives code that is directly generated from the DTD. This code will most likely be a functional Python script that is a fairly direct translation of the DTD. Ie. when the DTD gives a definition for the element "foobar", the Python script will have a function "foobar" that contains further function calls depending on the structure of the element in the DTD. The Python script is called on encountering the top element and from there on, the Python script and the syntax analyzer act in concert to build a document object.

By generating code instead of data from the DTD, I think it is possible to make the parsing stage a lot easier than when writing a data-driven flexible parser. Later versions can generate Java code and compile it on-the-fly or even write byte code directly.

Interaction with the GUI

The GUI contains the View and Controller components of the MVC triangle. The View is the representation of the canvas on which the model is shown, the Controller is the object that modifies the Model (presumably in reaction on user input like keystrokes, mouse actions, etcetera). I want to have a reasonably strict separation between these three parts. This is because with a good implementation of the MVC pattern it becomes trivial to hook multiple views and controllers to a single model - this makes collaborative applications a non-issue to implement: every user just connects it's own V/C to the model, and off you are. Furthermore, the Java Swing toolkit encourages this separation and makes it easy to implement.

Controlling the UI: Input and Display Stylesheets

An editor environment, where you can write text inside a text area, is not always what is optimal for the task at hand when entering information. For SGML, there are some alternative UI elements that should be available:

Furthermore, there is a strict distinction between input and display of the Model: for input of a bibliographic entry, a separate dialog might pop up; when the dialog is closed, the entry appears rendered in place in the document like a standard bibliographic reference. A lot of elements can be keyed in in place, but have special attributes when displaying (a CODE element may be entered like any other text, but will likely be rendered in a non-proportional font).

Therefore, each DTD needs to come with two stylesheets: one will control the Controller, this is the Input Stylesheet, and one will control the View, this is the Display Stylesheet. The Display Stylesheet presumably can be implemented in straight DSSSL; however, as DSSSL is not available (yet) within Java, it is likely that some simple alternative will be considered first (be it XSL, CSS or, most likely at the outset, homebrew stylesheet language based on Python). The Input Stylesheet is radically different from normal stylesheets, and needs to be able to call and activate all kinds of GUI elements; it will therefore be defined to use Python.

The idea is that the Controller knows the current position in the Model, and this knowledge is used to ask the Input Stylesheet for an input method - this can return nothing (in which case the default method, text editing, is used) or some code that needs to be run with a pointer to the relevant part of the Model; this code will simply activate some UI components and (temporarily) connect a different Controller (and View) to the Model.

Input Stylesheets should also be defined so that they can return alternate input methods, with attributes to flag the alternates. In this way, a DTD with a simple table model can return the default input method (in-line text editing) for tables but also an optional input method pointing to a table editor. In this case, the user will normally edit the table in the text editor, using explicit tags to mark up table elements, but at the same time has the option of activating (one of) the alternate input method(s), like a table editor. In collaborative environments, it should be possible that user one edits the table "manually", while user two views (and possibly modifies) the table in a table editor or even a spreadsheet.

Input V/C's should be able to register in some standard way. Some standard technique like InfoBus might be appropriate here.


PrevHomeNext
Key Technologies Document Threading