LOM

From LMNLWiki

This is a proposal by John Cowan. It is rooted in XOM rather than DOM, as I think XOM is a better design. It's also designed around classes, not interfaces, although in some languages an interface-based implementation might be better.

Needs to be updated to change Ranges into sets.

LOM is a whole-document LMNL Object Model. It's meant for practical use; don't confuse it with the LMNL data model.

See also Parser interface.

Node: the abstract parent class of almost everything else.

class Node {
   readonly Document property Document
   
   Node method copy()                       # deep copy
   method detach()                          # remove from owner
   method equal(Object obj)
   integer hashCode
   String method toString                   # short text for debugging
   String method toLMNL                     # serialize in LMNL syntax
}

Document: a whole document, carrying the Limen of the main text and the overall base URI.

class Document : Node {
   String property baseURI
   Limen property value
}

Limen: contains content and ranges; you can view the content in a variety of ways, and manipulate it as such.

class Limen : Node {
   readonly Node property owner

   # Manipulate content as child nodes
   Node method getChild(integer i)
   method setChild(integer i, Node newchild)
   method insertChild(integer i, Node newchild)
   method appendChild(Node newchild)
   method removeChild(integer i)
   method removeChild(Node child)
   method replaceChild(integer i, Node newchild)
   method replaceChild(Node child, Node newchild)
   integer method getChildCount()

   # Manipulate content as text (uses #xFFFD for non-character atoms)
   String method getText(integer start, integer end)
   method setText(integer start, integer end, String newtext)
   method insertText(integer point, String newtext)
   method appendText(String newtext)
   method removeText(integer start, integer end)
   method replaceText(integer start, integer end, String newtext)
   integer method length()

   # Manipulate content as atoms
   Atom method getAtom(integer point)       # get Atom after point
   method setAtom(integer point)            # replace Atom after point

   # Manipulate ranges over content
   Range method getRange(integer i)
   method setRange(integer i)
   method insertRange(Range newrange, integer i)
   method appendRange(Range newrange)
   method removeRange(integer i)
   method removeRange(Range range)
   method replaceRange(integer i, Range newrange)
   method replaceRange(Range range, Range newrange)
   integer method getRangeCount()

   method boolean contains(Node node)
   method indexOf(Node node)
   method Limen overlay()                   # return new Limen owned by this one,
                                            # whose content is an ordered subset of this one's ranges
}

Annotatable: an intermediate abstract class for the things that can carry annotations, namely ranges, atoms, and other annotations.

class Annotatable : Node {
   Annotation method getAnnotation(integer i)
   Annotations method getAnnotations()
   method setAnnotation(integer i, Annotation newannotation)
   method insertAnnotation(integer i, Annotation newAnnotation)
   method appendAnnotation(Annotation newAnnotation)
   method removeAnnotation(integer i)
   method removeAnnotation(Annotation annotation)
   method replaceAnnotation(integer i, Annotation newannotation)
   method replaceAnnotation(Annotation annotation, Annotation newAnnotation)
}

Range: over atoms or other ranges. Every range is part of just one Limen. The range relationships are represented here as well.

class Range : Annotatable {
   String property namespaceName
   String property localpart
   integer property start
   integer property end
   integer method length()
   integer method text()
   boolean method congruent(Range r)
   boolean method encloses(Range r)
   boolean method strictlyEncloses(Range r)
   boolean method enclosesWithSuffix(Range r)
   boolean method enclosesWithPrefix(Range r)
   boolean method fitsWithin(Range r)
   boolean method fitsStrictlyWithin(Range r)
   boolean method isPrefixOf(Range r)
   boolean method isSuffixOf(Range r)
   boolean method overlaps(Range r)
   boolean method overlapsStartOf(Range r)
   boolean method overlapsEndOf(Range r)
   boolean method precedes(Range r)
   boolean method strictlyPrecedes(Range r)
   boolean method immediatelyPrecedes(Range r)
   boolean method follows(Range r)
   boolean method strictlyFollows(Range r)
   boolean method immediatelyFollows(Range r)
   boolean method before(Range r)
   boolean method after(Range r)
}

Annotation: most properties and methods are in Annotatable or Node.

class Annotation : Annotatable {
   String property namespaceName
   String property localpart
   Limen property value
}

Atom: most properties and methods are in Annotatable or Node.

class Atom : Annotatable {
   String property namespaceName
   String property localpart
}

Comment: not part of the data model, but we represent them so that you can round-trip LMNL documents through LOM.

class Comment : Node {
   String property content
}

Text: a holder for textual content. We need to have these for efficiency; we can't use native String because we need Text to be a subtype of Node.

class Text : Node {
   String property content
}

Nodes: a dead list of Nodes (the nodes can change, but which nodes belong to a Nodes does not change unless you change it).

class Nodes {
   Node method get(integer i)
   Node method insert(integer i, Node newnode)
   Node method add(Node newnode)
   Node method remove(integer i)
   Node method remove(Node node)
   Node method replace(integer i, Node newnode)
   Node method replace(Node node, Node newnode)
   integer method count()
   boolean method contains(Node node)
}

Annotations: like Nodes, but specialized to hold annotations. Not a subclass of Nodes, because that would require covariant method arguments, which are unsound.

class Annotations {
   Annotation method get(integer i)
   Annotation method insert(integer i, Annotation newnode)
   Annotation method add(Annotation annotation)
   Annotation method remove(integer i)
   Annotation method remove(Annotation annotation)
   Annotation method replace(integer i, Annotation newannotation)
   Annotation method replace(Annotation annotation, Annotation newannotation)
   integer method count()
   boolean method contains(Annotation annotation)
}

Builder: how we build LOM Documents. You can supply a Parser as a source of LMNL events, and a NodeFactory to construct Nodes.

class Builder {
   Parser property parser
   NodeFactory property nodeFactory
   method build(File f)
   method build(InputStream i)
   method build(InputStream i, String baseURI)
   method build(Reader r)
   method build(Reader r, String baseURI)
   method build(String sourceURI)
   method build(String document, String baseURI)
}

NodeFactory: subclassing this class allows the user to get complete control of what Nodes are created when and how the Document is built. By overriding various methods you can construct e.g. subdocuments based on particular annotations while discarding the main document.

class NodeFactory {
   Document method startMakingDocument()
   Nodes method endMakingDocument(Document document)
   Range method startMakingRange(Limen owner, String namespaceName, String localpart)
   Nodes method endMakingRange(Range range)
   Annotation method startMakingAnnotation(Annotatable owner, String namespaceName, string localpart)
   Nodes method endMakingAnnotation(Annotation annotation)
   Atom method startMakingAtom(Limen owner, String namespaceName, String localpart)
   Nodes method endMakingAtom(Atom atom)
   Nodes method makeText(char[] characters, integer start, integer end)
   Nodes method makeComment(String comment)
}