@apertura/ooxml
Shared Office Open XML layer: ZIP container, OPC package, relationships, XML parsing
117 exported symbols · 117 declared here · 0 re-exported
Classes
Resolves package parts into URLs usable by `<img>` and CSS, and owns their lifetime. Two problems are solved here that every naive implementation gets wrong. First, leaks: an object URL is a document-lifetime handle to the underlying blob. A viewer that creates one per image render and never revokes it keeps every version of every image alive for as long as the page lives. The resolver hands out URLs and revokes all of them on {@link dispose}. Second, duplication: the same image is routinely referenced from many places (a logo in a header repeated on every page). Caching by part name means the bytes are inflated once and the browser decodes one image instead of dozens. How a URL is minted is not decided here — see {@link MediaUrlFactory}. That indirection is what lets this class, which sits under every parser, be loaded on a server.
An OPC package (Open Packaging Conventions, ECMA-376 part 2). The shared container of docx, xlsx and pptx: a ZIP archive in which `[Content_Types].xml` assigns MIME types to parts and `.rels` files link parts to each other. Parsing this layer is identical for all three formats, so it lives apart from the format-specific packages.
A streaming (pull) XML parser. This is the foundation of the whole OOXML layer and the reason large documents stay fast. Building a full node tree for a 40 MB `document.xml` costs several hundred megabytes and a second of allocation before any useful work starts. A pull parser lets the consumer walk the file once and build only the domain model it actually needs, allocating nothing per element it chooses to skip. Design notes that matter for performance: - Element and namespace names are interned. A document contains millions of `w:t`/`w:r`/`w:p` tags but only a few dozen distinct names, so interning turns name comparison into pointer comparison and removes almost all string allocation. - Attributes are parsed lazily. Most elements are visited without their attributes ever being read, so they are only materialised on demand. - Text is decoded lazily. Whitespace-only text between tags is extremely common and is skipped without ever becoming a JavaScript string. The parser deliberately supports no DTD or external entities: office files never use them, and processing them is a well-known vulnerability class (XXE).
Random-access ZIP archive reader. Works on top of a {@link ByteSource} rather than an in-memory buffer: listing the contents of a 100 MB xlsx only requires reading a few kilobytes of central directory at the end of the file. Individual entries are inflated on demand, which is essential for large workbooks where most of the weight sits in one or two sheets that may never be opened.
Functions
Attribute value. Unprefixed attributes are looked up with an empty namespace.
Boolean attribute in the OOXML sense. In the `ST_OnOff` schema `1`, `true` and `on` mean true; the absence of the attribute on a flag element (such as `<w:b/>`) also means true.
Numeric attribute value; `undefined` when absent or not a number.
First direct child with the given name.
Direct child elements; text nodes are dropped.
All direct children with the given name.
Data URIs: work everywhere, cost a third more memory, need no revoking.
Decodes a packed DIB — header, palette and bits in one run of bytes.
Expands predefined entities and numeric character references.
Object URLs where the host has them, data URIs otherwise.
All descendants at any depth with the given name.
Determines the concrete OOXML format from the type of the main part. This is the refinement the core cannot make: docx, xlsx and pptx are the same ZIP with the same signature, and only `[Content_Types].xml` tells them apart. File extensions are unreliable — renamed files turn up constantly — so the decision is made from the contents.
Base64, by hand. `btoa` is a browser function and `Buffer` is a Node one, and this package has a hard rule against needing either. Three bytes to four characters is twenty lines and no dependency; the alternative is a runtime check on the hot path of every image in a workbook.
Encodes 8-bit RGBA pixels, top row first, as a PNG.
First descendant at any depth with the given name.
Infers an image MIME type from its magic bytes. `[Content_Types].xml` usually declares media types, but files written by third-party generators often omit the entry for an extension, and a blob with the wrong type simply fails to render.
Interprets an `ST_OnOff` value.
Image types that no browser can render natively.
Converts a metafile into an SVG document.
Normalises a part name: no leading slash, forward slashes only.
Object URLs: a handle to the bytes, revoked on dispose. Returns `undefined` where the host has no `URL.createObjectURL`, so a caller that specifically wants object URLs can tell that it did not get them rather than discovering it later through memory that never comes back.
Parses XML into a node tree. Built on top of {@link XmlPullParser} so there is exactly one lexer in the codebase. The tree form is the right tool for the small configuration parts of an OOXML package — `styles.xml`, `numbering.xml`, `theme1.xml`, `.rels` — which are read in full, revisited repeatedly, and small enough that the convenience of random access outweighs the allocation cost. For `document.xml`, worksheets and slides, use the pull parser directly: those parts are read once, sequentially, and can be several tens of megabytes.
Reads document metadata from `docProps/core.xml`, `app.xml` and `custom.xml`. Parsing is identical for docx, xlsx and pptx because this is part of OPC, not of any specific format. All three parts are optional: files produced by third-party generators frequently omit them, and their absence must not stop the document from opening.
Path of a part's `.rels` file: `word/document.xml` → `word/_rels/document.xml.rels`.
Resolves a relationship target relative to its owning part. Targets come both absolute (`/word/media/image1.png`) and relative (`../media/image1.png`); both forms appear in files written by real Word.
True when the host can mint object URLs.
All text in the subtree, concatenated in document order.
The picture a legacy embedded object was saved with, out of the VML drawing that holds it. An embedded object — a worksheet, a document, a chart of another application — is drawn by its own program, which no reader has. What every reader draws instead is the picture of it the file was saved with. Modern files put that picture where it can be found, in the `mc:Fallback` beside the object. Older ones do not: the object carries an `spid` and nothing else, and the picture is a VML shape of that id in a separate drawing part, related to the slide. That is not a historical curiosity. Of the 146 embedded objects in the presentation corpus, 45 are of this shape, and every one of them has the picture in the VML — so a reader that stops at `mc:Fallback` draws a third of the embedded objects it meets as nothing at all. Worth 121 lines of the 134389 the corpus compares, against a ceiling of about a thousand, and the gap between those two numbers has a cause worth knowing: PowerPoint does not always draw these as text either. `npoi/45541_Footer` embeds a slide whose preview holds a hundred words; PowerPoint's own export rasterises it and writes two. Drawing the preview is right for a reader — the words are on the screen and can be selected — and the reference happens not to reward it.
Depth-first traversal of the subtree, including the element itself.
Interfaces
Device-independent bitmaps, as a metafile carries them. A DIB is what Windows called an image before there were image formats: a header, a palette when the depth needs one, and rows of pixels stored bottom to top and padded to a multiple of four bytes. Every bitmap inside an EMF or a WMF is one of these, so reading them is the difference between a diagram with its screenshots and a diagram with holes. The two headers that occur are the ancient `BITMAPCOREHEADER` and the `BITMAPINFOHEADER` everything since 1995 writes; both are read, because a metafile pasted from a twenty-year-old document really does contain the first.
Mints and releases URLs for media parts.
A relationship between package parts (`.rels`).
An XML attribute with its namespace resolved.
Options controlling how the archive caches inflated entries.
One entry of the ZIP central directory.
Type aliases
Values
Content types of main parts; used to identify the document format.
OPC package parts: content types and relationships.
Document metadata.
DrawingML — shared graphics for all three formats.
SmartArt: the diagram definition, and the shapes Word laid out from it. The definition namespace is part of the standard, but the laid-out result is not: Word writes it under a Microsoft namespace as an extension. That drawing is what makes SmartArt viewable at all without reimplementing the diagram layout algorithms, so a reader that ignores extension parts renders nothing.
Markup Compatibility and Extensibility: `mc:AlternateContent` fallbacks.
Office Math Markup Language, used for equations.
The `r:id` reference namespace used inside document parts.
PresentationML — pptx.
SpreadsheetML — xlsx.
The two namespaces Excel's own extensions live in. Everything added after the schema was published — sparklines, the newer conditional formats, slicers — is written inside an `extLst` under these, so that a reader of the published schema steps over what it cannot know.
VML: the legacy vector format still emitted by Word for text boxes and shapes.
Word 2010+ extensions, where later features such as `w14:` live.
Shapes and text boxes as Word has written them since 2010. These appear only inside `mc:AlternateContent`, paired with a VML fallback for readers that predate them. The modern branch is the one that carries the text of a text box as ordinary WordprocessingML.
WordprocessingML — docx.
The reserved `xml:` namespace, needed for `xml:space="preserve"`.
Relationship types used to locate the key parts of a document.
Enums
Kind of the event the pull parser is currently positioned on. Numeric rather than string-valued, so the hot dispatch loop in the document parser compares integers. A plain enum rather than a `const enum` because the values cross package boundaries, which ambient const enums cannot do under `verbatimModuleSyntax`.