Purpose: explain the container model shared by the three formats and how opcPackage reads and writes it.
Prerequisites: none beyond Getting started; the module is opcPackage (sub-path @awacloud/ooxml/opc).
Every OOXML format (.docx, .xlsx, .pptx) shares the same
foundation: a ZIP container whose internal structure is governed by
ECMA-376 part 2 — Open Packaging Conventions.
Minimal anatomy
An OOXML package contains at least:
mydoc.docx (ZIP container)
├── [Content_Types].xml ← required, at the root
├── _rels/
│ └── .rels ← package-level relationships
└── word/ (format-specific prefix — word/, xl/, ppt/)
├── document.xml ← main part
└── _rels/
└── document.xml.rels ← document.xml's relationships (if needed)
Three roles
-
The ZIP container (RFC ZIP, ISO/IEC 21320-1).
@awacloud/ooxmlrelies on@awacloud/fw/io/compress/zip.js(DEFLATE + ZIP64), zero external dependency. -
[Content_Types].xmldeclares the MIME type of each part:<Default Extension="…" ContentType="…"/>— by file extension.<Override PartName="/abs/path" ContentType="…"/>— for a specific part. Overrides take precedence over defaults.
-
Relationships (
*.rels) — a typed graph between parts._rels/.relsat the package root: "package-level" relationships, typically the pointer to the main part (officeDocument).<dir>/_rels/<file>.rels: relationships owned by<dir>/<file>.- A
TypeURI identifies the nature of the relationship (…/officeDocument,…/styles,…/image, …).
Read cycle (opc.read(bytes))
- Decompress the ZIP with
unzipSync. - Read
[Content_Types].xml→{ defaults, overrides }. - For each entry:
- If it matches
*.rels(path containing_rels/), parse it as relationships and attribute it to its owning part (/word/document.xml.rels→/word/document.xml,_rels/.rels→/). - Otherwise, store the raw
Uint8Arrayunder its absolute part name (/word/document.xml).
- If it matches
- Return
{ contentTypes, parts, rels }.
The format modules (docx/xlsx/pptx) then consume this package: they
follow the relationships to reach the main part (via the
officeDocument type) and delegate to their own XML parser.
Write cycle (opc.write(pkg))
- Serialize
[Content_Types].xmlfrompkg.contentTypes. - For each relationship set in
pkg.rels, serialize it under the corresponding*.relspath (opcRelationships.relsPathFor). - Include each part of
pkg.partsat its path (stripped of the leading/). - Package everything via
zipSync, every entry stamped 1980-01-01 00:00 unlessopts.mtimeis given.
Naming conventions
- Part name — always absolute, starts with
/(/word/document.xml). On the ZIP side, the path has no leading/—opc.read/opc.writehandle the conversion. - Target in relationships — relative by default to the source's
directory.
opcRelationships.resolveTarget(source, target)computes the absolute path.
See also
- ECMA-376 part 2 (Open Packaging Conventions), 5th edition, December 2021 — the Ecma International standard this layer implements.
src/opc/package.js— implementation.opcPackageAPI reference — full method signatures, including theooxmlShareddependency added by the L4 finalization.