How to cite this paper
Pemberton, Steven. “Designing a Notation Using ixml.” Presented at Balisage: The Markup Conference 2026, Washington, DC, August 3 - 7, 2026. In Proceedings of Balisage: The Markup Conference 2026. Balisage Series on Markup Technologies, vol. 31 (2026). https://doi.org/10.4242/BalisageVol31.Pemberton01.
Balisage: The Markup Conference 2026
August 3 - 7, 2026
Balisage Paper: Designing a Notation Using ixml
Steven Pemberton
Researcher
CWI, Amsterdam
Steven Pemberton is a researcher affiliated with CWI,
Amsterdam. His research is in interaction, and how the
underlying software architecture can support users.
He co-designed the ABC programming language that formed
the basis for Python and was one of the first handful of
people on the open internet in Europe, when the CWI set it up
in 1988. Involved with the Web from the beginning, he
organised two workshops at the first Web Conference in
1994. For the best part of a decade he chaired the W3C HTML
working group, and has co-authored many web standards,
including HTML, XHTML, CSS, XForms and RDFa. He now chairs
the W3C XForms and Invisible Markup groups.
In 2022, ACM SIGCHI awarded him the Lifetime Practice Award.
More details at https://www.cwi.nl/~steven
Abstract
The original design of ixml did not focus on converting text files
into particular XML document types, but converting them to some
XML document type for further transformation. However, the other
direction is possible: if you have a particular document type, you
can design a textual notation for it. This paper treats a
particular use case, in order to reveal some of the options and
techniques available to designers of such a notation.
Table of Contents
- Introduction
- The Approach
- Recognising Input
- A Reminder About Spacing
- Namespaces
- Content
- Simple Controls
- Common Attributes
- The Model
- Container Controls
- Actions
- Submission
- Embedded XML
- Conclusion
Introduction
The ixml language ixml was
originally designed with the principal aim of allowing
non-marked-up textual documents to be treated as if they were XML
documents with markup. This can be seen as part of a progression
of abstractions being made on documents:
-
originally there were individual (proprietary) documents,
where each program that read them had to have have a special
input routine for that format of data, with built-in knowledge
of the underlying structure;
-
introducing markup made the structure explicit, and enabled
all data in all programs to be read by a single input routine;
-
however, the marked-up data would often include markup to
detail the presentation details; the introduction of style
sheets added an abstraction layer that extracted the
presentation into a separate file, which subsequently could be
used for a whole class of similar documents;
-
in the same way, ixml abstracts even the
markup out of the documents into a
separate file, similarly usable for a whole class of related
documents.
The original design of ixml was not to convert textual documents
to any particular XML document types, but
just to get a textual document into an initial XML form that could
later be refined as necessary using existing XML tools. So if you
had an existing XML document type, it was unlikely to be
producable with ixml directly, but only by producing an
intermediate document type with ixml, and transforming that to the
target document type with other tools.
However it is possible to work in the other direction, that is to
say, if you have an existing XML document type, that doesn't have
a particular flat textual equivalent already, you can use ixml to
design a textual representation for it. People often seem to
prefer authoring flat textual documents, because they can see and
understand the structure unaided, and find the need to add markup
to make it readable for computers a distraction. An example of
this is Markdown
md, which is a
flat version of (X)HTML. Indeed there is an example of ixml being
used to process Markdown in exactly this way
adv.
In an earlier ixml paper on Modularisation
m12n, there was a hint of such an
approach for XForms xf which exists
as an XML language with no equivalent textual form; in that paper
it was used to demonstrate the application of modularisation on a
large example. In this paper we take this further, and examine the
processes you have to go through to design a flat textual
notation, and the options you have, and techniques you can use,
using XForms as the target language.
The Approach
The most important, and distinguishing factor of designing a
notation for an existing XML document type is that the structure
has already been specified: there are no decisions to be made on
that front. As pointed out in the earlier example of defining ixml
for markdown, the top level ixml rules for Markdown
must be html,
head, and body, since they
have to match the final target structure.
Similarly in the case of XForms, the overall structure of the
rules has already been decided for us, which we can determine
directly from the XForms schema, thus giving at the top level the
ixml rules:
model: (instance; bind; action; submission)*.
-Content: Controls.
-Controls: Core-Controls; group; switch; repeat.
-Core-Controls: input; secret; textarea; output; upload;
range; trigger; submit; select; select1.
(as in the XForms specification, all rule names with an initial
lower-case letter are used for actual elements that will occur in
the output, and names with an initial capital for other rules).
Of course, XForms wasn't designed to be a standalone language, but
one embedded in other languages, so we need to specify a top-level
structure in a host language, in this case XHTML:
html: head, body.
where head contains the models, and
body contains the content. For instance:
head: title, Style*, model+.
body: Content.
Recognising Input
There are two approaches to recognising input: either by position,
or by adding extra characters to identify what we are dealing
with.
For instance, since the title is the first item in the head, we
can just use positioning and require that the first line be the
title of our XForm:
title: ~[#a]+, nl.
The rule for nl requires a newline, and allows
extra optional trailing space:
-nl: -#a, s?.
The rule for s is to allow trailing space, but
we will also use it where spacing is required, not just optional:
-s: -[" "; #9; #a]+.
For styling we use extra characters to identify the input, in this
case the word "style". Although it would also be
possible to allow embedded CSS, to keep it simple we will just use
html link elements:
Style: -"style", s, link.
link: href, Style-type, Style-rel.
@href: URL.
@Style-type>type: +"text/css".
@Style-rel>rel: +"stylesheet".
-URL: [L;"0"-"9"; ":/@.~#?"]+. {A simple version for now}
This requires a URL, and adds two other attributes to the output.
Note how ixml renaming has been used; although this is not yet
officially part of ixml, it is in the evolving future
specification ixml2 and in all
implementations. Also note the use of insertions to provide fixed
content for some elements. So if a flat XForm begins:
XForm Example
style app.css
we will get an output that starts:
<html>
<head>
<title>XForm Example</title>
<link href='app.css' type='text/css' rel='stylesheet'/>
A Reminder About Spacing
Although this has been treated elsewhere
adv, it is worth pointing out the
best technique for dealing with white space, since it is an easy
source of ambiguity.
The first tip is: consume extraneous spaces
after recognising a symbol. For instance:
name: [L]+, s?.
In that way, having recognised a name, the
parser is positioned at the next meaningful (i.e., non-space)
character, and doesn't have to try lots of different rules
beginning with a space. It also means that extra whitespace at the
end of the document is already dealt with.
Secondly: recognise spaces as early as possible. Do this:
id: -"#", name.
-name: [L]+, s?.
and not this:
id: -"#", name, s?.
-name: [L]+.
and certainly never this:
id: -"#", name, s?.
-name: [L]+, s?.
because in that case, if you had #abc followed
by a space, the parser wouldn't know whether the space was a part
of id or name, in other
words, you would get an ambiguous parse.
Namespaces
This brings us to the sticky question of namespaces; sticky,
because at the time of writing, the issue is not yet resolved in
the working group.
The XML design group did a clever thing when designing a notation
for namespaces xmlns: they designed
the namespace declarations to look like attributes, so that XML
documents would be syntactically compatible with earlier software.
Thus although namespace declarations look
like attributes, they have a different semantic interpretation
because they begin with the characters xmlns.
It is this author's opinion that since ixml is just producing an
XML document, it can use the same approach, by specifying that
things that look like attributes should be interpreted as
namespace declarations if the serialisation of the node starts
with the letters xmlns. For implementations
that produce textual output, this adds no extra processing; for
implementations that go directly to an XML internal form, the
namespace declarations have to be recognised and handled
appropriately.
Accepting this, we can redefine the html rule
to include a namespace in this way:
html: xhtml-ns, head, body.
@xhtml-ns>xmlns: +"http://www.w3.org/1999/xhtml".
which will give:
<html xmlns='http://www.w3.org/1999/xhtml'>
Content
We can use a similar approach to enclose the XForms controls in
the body in an element that declares the namespace:
body: Content.
Content>group: xf-ns, Controls.
@xf-ns>xmlns: +"http://www.w3.org/2002/xforms".
-Controls: Control*.
-Control: CoreControl; group; switch; repeat.
-CoreControl: input; secret; textarea; output; upload;
range; trigger; submit; select; select1.
which will give:
<body>
<group xmlns='http://www.w3.org/2002/xforms'>
Simple Controls
Most controls have a number of required parameters, and a number
of optional ones. For instance, consider input:
<input ref="person/@age">
<label>Age</label>
</input>
We can define this using positioning after a leading keyword:
input person/@age "Age"
like this:
input: -"input", s, ref, label.
@ref: XPath.
label: -'"', ~['"'; #a]*, -'"', s?.
XPath: [L; "0"-"9"; "/:@[]()+-*'><!=."]+, s?. {A simple version for now}
There's one other useful attribute for several controls, and that
is incremental="true" that specifies
that the control activates for every character typed. Since
incremental="false" is the default,
we don't have to specify it, so you can write:
input person/@age "Age" incremental
by changing the rule for input to:
input: -"input", s, ref, label, incremental?.
@incremental: -"incremental", +"true", s?.
so that we get:
<input ref='person/@age' incremental='true'>
<label>Age</label>
</input>
Common Attributes
Nearly all elements in XForms can have certain common attributes,
in particular class for presentation purposes,
and id for identification.
<output class="error" id="out1" ref="message">
<label>Error</label>
</input>
One option would be to give these a keyword to identify them:
output class:error id:out1 message "Error"
but another would be to use the same notation as used in CSS
css:
output.error #out1 message "Error"
like this:
output: -"output", class?, id?, ref, label.
@class: -".", name.
@id: -"#", name.
-name: [L], [L; "0"-"9"]+, s?.
We can group them together as Common attributes:
-Common: class?, id?.
and use them everywhere:
output: -"output", Common, ref, label.
The Model
Going back to the definition of the head:
head: title, Style*, model+.
we have to define the model. For instance:
model: "model", s, id?, Model-content.
-Model-content: (instance; bind; Action; submission)*.
instance: -"data", s, id?, src.
@src: URL.
bind: -"properties", s, ref, Property+.
-Property: type; constraint; relevant; required; readonly.
@type: -"type:", s?, name.
@constraint: -"constraint:", s?, Expression.
-Expression: XPath.
(we'll come back to Action and
submission later), looking like this:
model
data people.xml
properties person/@age type:integer constraint:.>0
As you can see, we are not obliged to use the same keywords in the
input as the elements in the output, so in this case, for example,
we have replaced the somewhat technical-sounding
instance with the more general
data, and bind with
properties.
To distinguish the various types of property in a bind, we have to
use keywords like this, however another approach would be to give
them each a separate definition:
-Model-content: (instance; Bind; Action; submission)*.
-Bind: Type; Constraint; Relevant; Required; Readonly.
Type>bind: -"type", s, ref, s, type.
@type: name.
Constraint>bind: -"constraint", s, ref, constraint.
@constraint: Expression.
etc., giving:
model
data people.xml
type person/@age integer
constraint person/@age .>0
yielding:
<model>
<instance src='people.xml'/>
<bind ref='person/@age' type='integer'/>
<bind ref='person/@age' constraint='.>0'/>
It is worth noting that nearly all XForms applications only have a
single model, so an alternative approach is to define models so
that in the simple (usual) case you don't have to declare a model
at all, only when there is more than one:
head: title, Style*, Models.
-Models: Single-model; model+.
-Single-model>model: Model-content.
model: -"model", s, id?, Model-content.
allowing in the simple case:
XForms Example
style app.css
data people.xml
type person/@age integer
constraint person/@age .>0
Container Controls
Some controls can contain other content, and be nested, the
simplest case being group:
<group>
...controls...
</group>
So we have a design a syntax for this style of control. Options
could include:
group:
...
:group
or
group
...
/group
or
group{
...
}group
or indeed
group {
...
}
It is also worth noting that controls that are not in themselves
principally containers, may nevertheless also contain content:
<input ref="person/@age">
<label>Age</label>
<dispatch name="CHANGED" targetid="m" ev:event="xforms-value-changed"/>
</input>
so it would be good if any syntax we choose be consistent with
these cases. For instance:
input person/@age "Age" {
dispatch CHANGED m xforms-value-changed
}
and
input person/@age "Age" {
hint "An integer"
}
We can do this by declaring a block:
-Block: -"{", s?, Controls, "}", s?.
and then define group as:
group: -"group", Common, ref?, label?, Block.
which requires a block, and
input: -"input", Common, ref, label, incremental?, Block?
where it is optional.
For the switch control, it could look like
this:
switch {
case #closed
trigger ">" {
toggle open DOMActivate
}
case #open
trigger "<" {
toggle close DOMActivate
}
repeat item {
output .
}
}
Defined like this:
switch: -"switch", Common, Cases.
-Cases: -"{", s?, case+, -"}", s?.
case: id, Controls.
Actions
XForms actions respond to asynchronous events that may occur. We
have already seen a few above, such as toggle,
and dispatch. These all have various
attributes, plus optionally an event that they are responding to.
For instance within a submission, a
setvalue might look like this.
<setvalue ref="message" ev:event="xforms-submit-error">Failed</setvalue>
We could represent this directly as:
setvalue message "Failed" xforms-submit-error
However, setvalue can also calculate a value:
<setvalue ref="count" value=".+1" ev:event="DOMActivate"/>
Luckily these two cases are syntactically distinguishable, so we
can define it as:
setvalue: -"setvalue", s, ref, (string; value), event.
@value: expression.
@event>"ev:event": name.
There is a grouping element for several actions, called
action:
<action ev:event="xforms-ready">
<setvalue ref="date" value="local-dateTime()"/>
<dispatch name="TICK" targetid="clock"/>
</action>
We can treat that in the same way that we treated
group earlier:
action: -"action", s, event, ActionBlock.
-ActionBlock: -"{", s?, Action*, -"}", s?.
-Action: toggle; setvalue; dispatch; action. {etc}
allowing:
action xforms-ready {
setvalue date local-dateTime()
dispatch TICK clock
}
However, we are not confined to doing it this way. Another
approach would express it as:
xforms-ready? {
setvalue date local-dateTime()
dispatch TICK clock
}
defined by:
action: event, -"?", s?, (Action; ActionBlock).
which would also allow:
DOMActivate? setvalue count .+1
Submission
The submission element is the most complex one
in XForms for the simple reason that HTTP submission is
complicated, and the element tries to cover all cases. Therefore
we will only address a subset of its features here.
A typical submission looks like this:
<submission id="save" method="put" ref="instance('data')"
resource="data.xml" replace="none">
<setvalue ref="message" ev:event="xforms-submit-error">Save failed</setvalue>
<setvalue ref="message" ev:event="xforms-submit-done"/>
</submission>
which could be represented like this:
submission #save put instance('data') data.xml replace:none {
xforms-submit-error? setvalue message "Save failed"
xforms-submit-done? setvalue message ""
}
However, this is such a common pattern, it might be worth
enforcing the handling of the return events, something like this:
submission #save put:instance('data') to:data.xml replace:none {
FAILURE setvalue message "Save failed"
SUCCESS setvalue message ""
}
along these lines:
submission: -"submission", Common, s, Method, resource, replace?, SubBlock.
-Method: PUT; GET; POST; DELETE; HEAD.
-PUT: method-put, ref.
-GET: method-get, ref.
@method-put>method: -"put:", +"PUT".
@method-get>method: -"get:", +"GET".
etc., and then define a Submission Block to allow the success and
failure parts in either order:
-SubBlock: -"{", s?, (SUCCESS, FAILURE; FAILURE, SUCCESS), -"}", s?.
SUCCESS>action: -"SUCCESS", s?, evSuccess, (Action; ActionBlock).
@evSuccess>"ev:event": +"xforms-submit-done".
FAILURE>action: -"FAILURE", s?, evFailure, (Action; ActionBlock).
@evFailure>"ev:event": +"xforms-submit-error".
giving an output like this:
<submission id='save' method='PUT' ref='instance('data')' resource='data.xml' replace='none'>
<action ev:event='xforms-submit-error'>
<setvalue ref='message'>Save failed</setvalue>
</action>
<action ev:event='xforms-submit-done'>
<setvalue ref='message'/>
</action>
</submission>
Embedded XML
Although we can easily embed and recognise other languages such as
CSS in our flat XForms, there is an irony that we can't embed raw
XML. This is partly because we can't get the names of the elements
into the output form (though see
gixml for an approach), and partly
because serialising "<" and ">"
characters would appear as "<" and
">", even if all we did was copy the embedded XML
from input to output.
Conclusion
This paper gives a taste of the option open to a format designer
wanting to use ixml. What we have presented is not a complete or
final design of a flat version of XForms, and there are still many
details that need to be completed. For instance, it would be
advantageous for the user if the structure of XPath is fully
defined, so that syntax errors on XPath expressions are identified
as early as possible.
Designing a text notation for a given XML Document type is an
interesting, even fun, exercise. While the overall structure of
the document is already established, the designer has a lot of
freedom in using keywords, extra characters, or positioning, to
identify syntactic forms. While at first unexpected, there is also
a lot of freedom in the choice of keywords and similar, that are
not required to match the terminology used in the document type.
References
[Advanced Tutorial] Steven Pemberton,
Advanced Invisible XML (ixml) Tutorial, CWI, 2025,
https://cwi.nl/~steven/ixml/advanced/
[CSS] Håkon Wium Lie et al. (eds.),
Cascading Style Sheets level 1, W3C, 1996,
https://www.w3.org/TR/CSS1/
[Generalised ixml] Steven Pemberton,
Generalised Invisible Markup
, Proc. Declarative Amsterdam, 2025,
https://declarative.amsterdam/article?doi=da.2025.pemberton.generalised-invisible-markup
[ixml] Steven Pemberton (ed.),
Invisible XML Specification, Invisible XML Organisation, 2022,
https://invisiblexml.org/1.0/
[Draft ixml] Steven Pemberton (ed.),
Invisible XML Specification Community Group Editorial Draft, Invisible XML Organisation, 2026,
https://invisiblexml.org/current/
[Modularised ixml] Steven Pemberton,
Modular ixml
, Proc. MarkupUK 2025, pp 6-20,
https://markupuk.org/pdf/proceedings-2025-2.pdf
[Markdown] John Gruber,
Markdown, Daring Fireball, 2004,
https://daringfireball.net/projects/markdown/
[XForms] Erik Bruchez et al. (eds.),
XForms 2.0, W3C, 2026,
https://www.w3.org/community/xformsusers/wiki/XForms_2.0
[Namespaces] Tim Bray et al.,
Namespaces in XML 1.0, W3C, 2009,
https://www.w3.org/TR/xml-names/