glepub/cfi
EPUB Canonical Fragment Identifiers — epubcfi(/6/4!/4/10/2:3) — the
standard way to address a point inside a publication.
A CFI is a path of child steps. Even indices address element children
(/2 is the first element child, /4 the second, …), odd indices the
text between them, and ! steps out of the package document into the
content document the itemref references. The part before the first !
identifies the spine item — SpineItem.cfi holds exactly that path —
and the rest addresses a node inside the chapter, optionally ending in
a :n character offset into a text node. A step may carry an
[assertion], usually the id the addressed element is expected to
have.
A range CFI — epubcfi(/6/4!/4/10/2,:1,:5) — addresses a stretch of
content between two such points: a shared parent path followed by two
local paths, one per endpoint. Range models one as its two absolute
endpoints, which is the shape every consumer wants — resolve either
endpoint like any point, compare points to sort ranges by document
position — and the shared-parent split is recomputed on printing.
This module parses and prints point and range CFIs and locates them in a book’s spine. The temporal/spatial offsets used for audio and images are not supported.
Types
pub type Cfi {
Cfi(parts: List(List(Step)), offset: option.Option(Int))
}
Constructors
-
Cfi(parts: List(List(Step)), offset: option.Option(Int))Arguments
- parts
-
One list of steps per document: the first walks the package document to an itemref, and each subsequent list follows a
!indirection into the referenced content document. - offset
-
The
:ncharacter offset into the text node the last step lands on.
A range CFI: two points in the same document, in document order. Build
one with range or parse_range; both uphold the invariants printing
relies on, so construction is the only place a range can fail.
pub opaque type Range
pub type Step {
Step(index: Int, assertion: option.Option(String))
}
Constructors
-
Step(index: Int, assertion: option.Option(String))Arguments
- index
-
Even for element children, odd for the text between them.
- assertion
-
The id the addressed element is asserted to have, from
[...].
Values
pub fn compare(a: Cfi, b: Cfi) -> order.Order
Document order over points: step by step down the tree, with a node sorting before its own contents, and character offsets breaking ties between points on the same node. Assertions do not participate.
pub fn locate(
cfi: Cfi,
) -> Result(#(Int, option.Option(Cfi)), Nil)
Split a publication-level CFI into the spine position it addresses and the remainder pointing within that chapter’s document, if any.
pub fn parse(text: String) -> Result(Cfi, Nil)
Parse an epubcfi(...) string addressing a single point. Range CFIs
are rejected here; use parse_range for them.
pub fn parse_range(text: String) -> Result(Range, Nil)
Parse an epubcfi(parent,start,end) range string. The two local paths
are joined onto the parent to make absolute endpoints; each may be a
run of steps, a bare :n offset, or empty (the endpoint is the parent
itself). Locals may not cross a ! indirection of their own.
pub fn path_to_string(cfi: Cfi) -> String
The CFI path without the epubcfi(...) wrapper — the form used for
the intra-document part of a fragment, and for joining onto a spine
item’s base path with !.
pub fn range(from from: Cfi, to to: Cfi) -> Result(Range, Nil)
Build a range from two points, normalising them into document order. The points must lie in the same document: every part but the last must match, and the final parts must share their first step — endpoints in different chapters do not form a range.
pub fn range_path_to_string(range: Range) -> String
The range’s path without the epubcfi(...) wrapper, for fragment use
and for joining onto a spine item’s base path with !.
pub fn range_to_string(range: Range) -> String
Print a range back out as an epubcfi(parent,start,end) string. The
printed form is canonical: the parent takes the maximal shared prefix
of the two endpoints, whatever split the range was parsed from.
pub fn spine_item(
book: glepub.Book,
cfi: Cfi,
) -> Result(#(glepub.SpineItem, option.Option(Cfi)), Nil)
The spine item a CFI addresses, with the remainder of the CFI pointing within that chapter’s document, if any.