DocxportNet 1.8.4
dotnet add package DocxportNet --version 1.8.4
NuGet\Install-Package DocxportNet -Version 1.8.4
<PackageReference Include="DocxportNet" Version="1.8.4" />
<PackageVersion Include="DocxportNet" Version="1.8.4" />
<PackageReference Include="DocxportNet" />
paket add DocxportNet --version 1.8.4
#r "nuget: DocxportNet, 1.8.4"
#:package DocxportNet@1.8.4
#addin nuget:?package=DocxportNet&version=1.8.4
#tool nuget:?package=DocxportNet&version=1.8.4
Docxport.Net
Docxport.Net is a .NET library for reading DOC and DOCX documents, exporting them to friendly formats, or rebuilding them as standalone DOCX files. Binary DOC inputs are projected to DOCX before walking. It handles:
- Tracked changes (accept/reject/inline views)
- Lists with proper markers and indentation
- Tables (including merged cells / spans)
- Comments and threaded replies
- Headers and footers
- Images/drawings
- Bookmarks, hyperlinks, fields, and more
See the web assembly in action here: https://gaspardpetit.github.io/Docxport.Net/demo/
Support overview
Input formats
- DOCX
- Binary DOC (projected to DOCX for export; fidelity varies by structure)
Output formats
- JSON metadata (
docxport my.doc --format=metadata; writes to stdout) - Markdown (rich + plain)
- HTML (rich + plain)
- Plain text
- DOCX (package-preserving rebuild with optional field evaluation)
- Binary DOC (writer with feature-dependent structure and formatting support)
Document features
- Tracked changes: accept/reject/inline/split modes
- Comments: threads + replies
- Lists: markers + indentation
- Tables: cell spanning (row/col), borders/background/vertical-align (incl.
tblStylepresets; theme colors/advanced border patterns are limited) - Headers/footers, bookmarks, hyperlinks, fields
- Images/drawings (best-effort)
Field evaluation & mail merge
- Word field evaluator with nested fields + formatting switches (
\*\#\@) - Mail‑merge control:
NEXT/NEXTIF/SKIPIF,MERGEREC/MERGESEQ - Merge macros:
GREETINGLINE/ADDRESSBLOCK(locale‑aware templates) - Pluggable
DATABASEprovider, including a provider-neutral ADO.NET adapter - Full checklist: docs/supported-fields.md
Field support (high‑level)
| Group | Fields | Status |
|---|---|---|
| Core | IF, SET, REF, DOCVARIABLE, DOCPROPERTY | ✅ |
| Dates | DATE, TIME, CREATEDATE, SAVEDATE, PRINTDATE | ✅ |
| Merge | MERGEFIELD, NEXT/NEXTIF/SKIPIF, MERGEREC/MERGESEQ | ✅ |
| Utilities | SEQ, COMPARE, ASK, Formula (=) | ◐ |
| Macros | GREETINGLINE, ADDRESSBLOCK | ◐ |
| Metrics | NUMPAGES, NUMWORDS, NUMCHARS | ◐ |
| Layout-dependent | PAGE, SECTION, SECTIONPAGES, PAGEREF | ◐ (cached result) |
| Indexing | TOC / INDEX / NOTEREF | ⛔ |
Legend: ✅ full, ◐ partial, ⛔ out of scope
Full checklist: docs/supported-fields.md
Why this exists
Most DOCX “save as text” pipelines lose important fidelity: strikethroughs and deletions disappear, list markers collapse to bullets or vanish (pandoc), comments/track changes are missing, images are dropped, and tools like LibreOffice/Interop require UI or platform-specific installs. Docxport.Net walks the OOXML directly, headlessly, and emits Markdown/HTML/plain text while preserving tracked changes, comments, list markers, images, headers/footers, and other semantics.
Pdfxport dependency
Normal builds use Pdfxport.Net and Pdfxport.Net.MigraDoc 7.0.2 from NuGet.
To test against a separate Pdfxport source checkout, provide its path:
dotnet build DocxportNet/DocxportNet.csproj -p:PdfSharpSourceRoot=D:\git\Pdfxport.Net
DxpPdfVisitor provides a text-focused PDF slice through the standard
DxpExport.ExportToBytes and ExportToFile APIs. It handles paragraphs, list
markers, explicit page breaks, line wrapping, page overflow, and effective run
font family, size, bold, and italic. It does not yet reproduce Word's full run
effects, tables, images, or page geometry. On net8.0, call
DxpPdfFonts.Configure() before PDF export to select installed fonts.
On net8.0, DxpFlowPdfVisitor provides the layout-oriented exporter through
the same APIs, including page geometry, tables, images, headers and footers,
notes, and drawing content. It is not included in the netstandard2.0 target;
that target retains DxpPdfVisitor until the flow implementation's newer .NET
API usage is ported. Applications can pass an IDxpPdfFontProvider to
DxpPdfFonts.Configure(provider) before PDF export. The provider maps a
requested family and style to font bytes. Browser hosts can download or bundle
fonts and register them before export; the callback must return synchronously.
Pass the same provider to DxpFlowPdfVisitor(fontProvider: provider) to let
layout check IsAvailable and ResolveForCharacter before measuring text.
ResolveForCharacter may choose a substitute family for an individual Unicode
character; Docxport splits the text at each font change. Providers that do not
implement character lookup retain the existing font selection behavior.
Pdfxport's font settings are process-wide, so configure the provider once at
startup and do not change it during concurrent exports.
Quick start: DOCX → Markdown
Command line
# Option A: Install the CLI as a .NET tool (recommended)
dotnet tool install -g DocxportNet.Cli
docxport my-doc.docx -o my-doc.md --tracked=accept
# Option B: Download a self-contained binary from GitHub Releases
# (pick your OS/arch zip, extract it, then run):
./docxport my-doc.docx -o my-doc.md --tracked=accept
# From source (development):
git clone https://github.com/gaspardpetit/Docxport.Net.git
dotnet run --project DocxportNet.Cli -- my-doc.docx -o my-doc.md --tracked=accept
NuGet + code
Install: dotnet add package DocxportNet
using DocxportNet;
using DocxportNet.Visitors.Markdown;
string docxPath = "my-doc.docx";
var visitor = new DxpMarkdownVisitor(DxpMarkdownVisitorConfig.RICH);
string markdown = DxpExport.ExportToString(docxPath, visitor);
File.WriteAllText(Path.ChangeExtension(docxPath, ".md"), markdown);
Resolve fields into a standalone DOCX
The DOCX exporter reuses the source package and rebuilds the main document,
headers, footers, footnotes, and endnotes from walker events. Data-dependent
fields can be resolved while Word layout fields such as PAGE, NUMPAGES,
SECTION, SECTIONPAGES, and PAGEREF remain native fields for Word to update.
docxport template.docx --fields=evaluate --vars=values.json -o resolved.docx
using DocxportNet;
using DocxportNet.Fields;
var fields = new DxpFieldEval();
fields.Context.SetDocVariable("Reference", "ABC-123");
DxpDocxExport.Export("template.docx", "resolved.docx", fieldEval: fields);
INCLUDETEXT resolution remains opt-in through an IDxpIncludeTextResolver.
Unsupported or unavailable field sources use the evaluator's existing cached-result behavior.
Tracked changes
Visitors can emit different views of tracked changes:
- Accept changes (default):
DxpTrackedChangeMode.AcceptChanges - Reject changes:
DxpTrackedChangeMode.RejectChanges - Inline markup (insert/delete):
DxpTrackedChangeMode.InlineChanges - Split accept/reject panes:
DxpTrackedChangeMode.SplitChanges
Pick the mode on the visitor config, e.g.:
var config = DxpMarkdownVisitorConfig.RICH with { TrackedChangeMode = DxpTrackedChangeMode.RejectChanges };
var rejectVisitor = new DxpMarkdownVisitor(config);
string rejected = DxpExport.ExportToString(docxPath, rejectVisitor);
Visitors and options
Markdown
- Presets:
DxpMarkdownVisitorConfig.CreateRichConfig()(styled) andCreatePlainConfig()(minimal); both default math to LaTeX with automatic$versus\(delimiters and\[blocks. SelectDollar,Backslash, orAutothroughMathDelimiterStyle. - Options cover images, inline styling, rich tables, comments formatting, custom properties, and tracked change mode.
HTML
- Preset:
DxpHtmlVisitorConfig.CreateRichConfig()(styled) andCreatePlainConfig()(minimal); both default math to native MathML. - Options cover inline styles, colors/backgrounds, table borders, document colors, headers/footers, comments mode, custom properties, timeline, and tracked change mode.
Plain text
- Presets:
DxpPlainTextVisitorConfig.CreateAcceptConfig()andCreateRejectConfig()(choose tracked change handling); both default math to readable text. - Focused on readable text output with list markers, comments, and basic structure.
DOCX
DxpDocxVisitorpreserves reusable package parts while rebuilding walked document stories.DxpDocxExportprovides convenient file and byte-array APIs.- DOCX rebuilding without a caller-supplied
DxpFieldEvalpreserves cachedREFandIFresults. Supplyingnew DxpExportOptions()has the same default. - A caller-supplied
DxpFieldEvalevaluates supported dependencies such asASK→REFand nestedIF→ASK. An explicitFieldEvalMode = Evaluatealso requests evaluation, even without a supplied evaluator. - Set
DocxFieldPolicy = DxpDocxFieldPolicy.PreserveorEvaluateto override that choice. Layout-dependent fields remain native during evaluation;FieldEvalMode = Nonedisables field processing andCachereplays cached results.
DxpExport has overloads for DOC and DOCX file paths and in-memory bytes, or an already-open WordprocessingDocument, and can return a string, a byte[], write straight to a file path, or just drive a visitor that collects data.
Document metadata
DxpMetadata.Inspect(path) or DxpMetadata.Inspect(bytes) reads DOCX and binary DOC metadata without converting the document. The result contains core properties, available application and document statistics, language ratios, HasTrackedChanges, and HasComments. DOC supplies fewer extended properties than DOCX; unavailable values are null. The browser package exposes the same result through await docxport.inspect(bytes).
CLI
A ready-to-use console app lives in DocxportNet.Cli and is published as a .NET tool. Example:
dotnet tool install -g DocxportNet.Cli
docxport my.docx -o my.md --tracked=accept
The CLI accepts .doc and .docx inputs. The output extension selects the format when --format is omitted:
docxport old.doc -o old.docx # DOC → DOCX
docxport modern.docx -o modern.doc # DOCX → DOC
docxport modern.docx -o modern.pdf # DOCX → PDF
docxport modern.docx -o modern.pdf --font-dir=./fonts
docxport old.doc --format=metadata # JSON metadata on stdout
docxport modern.docx -o modern.json # JSON metadata in a file
Metadata includes core properties, available statistics and languages, and flags for tracked changes and comments. Conversion fidelity depends on the structures in the source. Without -o, --format=docx writes <name>.resolved.docx, --format=doc writes <name>.plain.doc, --format=pdf writes <name>.pdf, and --format=metadata writes JSON to stdout. Other formats write beside the input with the selected output extension.
Self-contained binaries for Windows/Linux/macOS are also published on GitHub Releases.
PDF export uses Pdfxport's Windows font discovery on Windows. On Linux and macOS
it uses fontconfig when available, with a small set of file-path fallbacks.
For reproducible output across machines, provide a fixed IDxpPdfFontProvider.
The CLI's repeatable --font-dir=directory option searches .ttf and .otf
files recursively by their embedded family and style names before installed
fonts. TrueType collections (.ttc) are not indexed by this option.
For fonts in those directories, the CLI checks glyph coverage and uses another
indexed face when the requested face lacks a character. Its installed-system
fallback does not yet perform this character-level check.
dotnet run --project DocxportNet.Cli -- my.docx -o my.md --tracked=accept
# or, using a self-contained binary:
./docxport my.docx --format=html --tracked=inline
Browser WebAssembly
DocxportNet.Wasm publishes the exporters as the browser-only docxport ESM package. It accepts DOC or DOCX data as a Uint8Array and returns HTML, Markdown, plain text, PDF bytes, or a resolved DOCX without uploading the document. PDF export requires OpenType font bytes supplied by the host through registerPdfFont.
dotnet workload install wasm-tools
./DocxportNet.Wasm/build-package.ps1
cd ./DocxportNet.Wasm/bin/Release/net10.0/publish/wwwroot
npm pack
Serve that wwwroot directory and open demo/ to run the standalone showcase. See the package README and index.d.ts for the JavaScript API and detailed exporter options.
Bundled applications copy the .NET runtime into their public assets before building:
npx docxport-copy-assets public/docxport
Then initialize with createDocxport({ assetBaseUrl: "/docxport/" }). The package README includes React, Vue, Vite, and generic static-hosting guidance.
Options: --format=markdown|html|text|docx|doc|pdf|metadata, --tracked=accept|reject|inline|split (text uses accept/reject), --plain (plain markdown/HTML), -o, --output=path (infers format from extension when --format is omitted), --vars=path (JSON/INI DOCVARIABLEs), -D name=value (repeatable overrides), --include-path=directory (repeatable allowed/search roots for evaluated DOCX and HTML INCLUDETEXT fields), and --font-dir=directory (repeatable additional PDF font roots).
docxport my.docx --fields=evaluate --include-path="C:\templates\Word Templates" -o my.md
Custom visitors
You can write your own DxpIVisitor to extract specific content. Example: collect all comments.
using DocxportNet.API;
using DocxportNet.Visitors;
using DocumentFormat.OpenXml.Wordprocessing;
public sealed class CommentCollector : DxpVisitor
{
public List<(string Author, string Text)> Comments { get; } = new();
public override void VisitComment(Comment c, DxpIDocumentContext d)
{
Comments.Add((c.Author?.Value ?? "Unknown", c.InnerText));
}
}
var collector = new CommentCollector();
DxpExport.Export("my-doc.docx", collector);
foreach (var (author, text) in collector.Comments)
Console.WriteLine($"{author}: {text}");
It also ships a small utility that translates legacy “symbol fonts” (Symbol, Zapf Dingbats, Webdings, Wingdings) into modern Unicode.
Field evaluation
Docxport.Net ships a standalone field evaluator for Word field codes. It can be used on its own or alongside the walker/exporter. For the exact language and field specifications, see docs/word-fields.md.
High‑level support includes:
- Core built‑ins:
DATE/TIME/CREATEDATE/SAVEDATE/PRINTDATE,SET/REF,DOCPROPERTY/DOCVARIABLE,MERGEFIELD,SEQ,IF/COMPARE/NEXTIF/SKIPIF,ASK - Formulas: arithmetic, comparisons, functions (
SUM/AVERAGE/etc.), nested fields, table cell references (via a resolver) - Formatting switches:
\*text transforms,\#numeric pictures,\@date/time pictures - Locale‑aware formatting and list‑separator handling
- Number‑to‑words languages: English, French, German, Spanish, Italian, Portuguese, Danish, Japanese, Thai, Chinese (Simplified)
- Recursive DOCX and HTML
INCLUDETEXT, including optional named bookmark ranges, through an opt-inIDxpIncludeTextResolver
HTML fragments are converted to an in-memory DOCX and use the same block-aware splice pipeline as DOCX fragments. External image references are preserved as authored but are never downloaded by Docxport.Net; valid data:image sources remain embedded. Resolvers may set DxpIncludeTextSource.Format when an alias or extensionless reference needs an explicit HTML/DOCX hint, and applications may replace DxpFieldEvalContext.HtmlToDocxConverter to customize conversion.
Minimal setup (standalone):
using DocxportNet.Fields;
var eval = new DxpFieldEval();
eval.Context.SetBookmark("Total", "123.45");
eval.Context.SetDocumentPropertyValue("Title", new DxpFieldValue("My Doc"));
var date = await eval.EvalAsync(new DxpFieldInstruction("DATE \\@ \"yyyy-MM-dd\""));
var cond = await eval.EvalAsync(new DxpFieldInstruction("IF Total > 100 \"Big\" \"Small\""));
var formula = await eval.EvalAsync(new DxpFieldInstruction("= Total * 2 \\# \"$#,##0.00\""));
var title = await eval.EvalAsync(new DxpFieldInstruction("DOCPROPERTY Title \\* Upper"));
// date.Text -> "2026-02-07" (uses default NowProvider)
// cond.Text -> "Big"
// formula.Text -> "$246.90"
// title.Text -> "MY DOC"
Minimal setup (with exporter + middleware):
using DocxportNet;
using DocxportNet.Fields;
using DocxportNet.Visitors.PlainText;
var visitor = new DxpPlainTextVisitor(DxpPlainTextVisitorConfig.CreateAcceptConfig());
// DxpExport wraps the visitor with field-eval middleware automatically.
string text = DxpExport.ExportToString("my-doc.docx", visitor);
Providing DOCVARIABLEs:
using DocxportNet.Fields;
var eval = new DxpFieldEval();
eval.Context.SetDocVariable("ClientName", "Contoso Ltd.");
var result = await eval.EvalAsync(new DxpFieldInstruction("DOCVARIABLE ClientName \\* Upper"));
// result.Text -> "CONTOSO LTD."
If you need dynamic resolution (DB/HTTP/etc.), register a resolver on the context instead of pre‑seeding values.
Gaps and contributions welcome
| Area | Current gap |
|---|---|
| List markers | Word supports exotic textual markers (“forty-two” in various languages); current formatter covers numeric/roman/alpha and supports text‑number formats via the shared number‑to‑words registry, but not every Word numbering style. |
| Shapes/SmartArt | Complex shapes/SmartArt/OLE rely on preview images if present; true vector or OLE rendering is not implemented. |
| Charts | Charts are emitted via available previews or placeholders; data-driven re-rendering is not implemented. |
| Math/Fields | Field evaluation exists, but complex math/field result rendering in exporters isn’t deeply covered by fixtures. |
| Tables (complex) | Table styles are partially supported (borders/background/vertical align, incl. tblStyle presets), but theme color resolution and advanced border patterns are still limited; nested/edge-case tables beyond supplied samples may need additional handling. |
Contributions that improve any of these areas are very welcome.
Supported symbol fonts
Symbols typically used in list markers are automatically converted to their unicode equivalent. Supported fonts include:
- Symbol
- Zapf Dingbats
- Webdings
- Wingdings
- Wingdings 2
- Wingdings 3
Symbol font to Unicode
Use DxpFontSymbols when you encounter text that was encoded with a symbol font and you want plain Unicode output.
// Convert a whole string using the font hint.
// 0x41 ('A') -> ✌, 0x42 ('B') -> 👌 in the Wingdings table.
string text = DxpFontSymbols.Substitute("Wingdings", "\u0041\u0042"); // => "✌👌"
// Convert a single character; falls back to the original if unmapped
string bullet = DxpFontSymbols.Substitute("Symbol", (char)0xB7); // → "•"
Unknown characters are returned unchanged. You can optionally supply a replacement character for non-printable glyphs:
// Replace non-printable/control entries with '?'
string safe = DxpFontSymbols.Substitute("Symbol", "\u0001\u00B7", '?'); // => "?•"
Reusing a converter
If you need to translate many strings from the same font or probe whether a font is supported, reuse a converter instance:
var converter = DxpFontSymbols.GetSymbolConverter("Webdings");
if (converter != null)
{
string cat = converter.Substitute((char)0xF6, '?'); // 🐈
string arrows = converter.Substitute((char)0x3C); // ↔
}
Common mappings
- Symbol bullet:
DxpFontSymbols.Substitute("Symbol", (char)0xB7)→• - Webdings cat:
DxpFontSymbols.Substitute("Webdings", (char)0xF6)→🐈 - Wingdings peace/ok:
DxpFontSymbols.Substitute("Wingdings", "\u0041\u0042")→✌👌 - Wingdings 2 left point:
DxpFontSymbols.Substitute("Wingdings 2", (char)0x42)→👈 - Wingdings 3 arrows:
DxpFontSymbols.Substitute("Wingdings 3", "\u0030\u0031")→⭽⭤
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- AngleSharp (>= 1.6.0)
- DocumentFormat.OpenXml (>= 3.5.1)
- HtmlToOpenXml.dll (>= 3.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Win32.Registry (>= 5.0.0)
- OpenMcdf (>= 3.3.0)
- PdfPig (>= 0.1.16)
- Pdfxport.Net (= 7.0.6)
- Pdfxport.Net.MigraDoc (= 7.0.6)
- StbImageSharp (>= 2.30.16)
- StbImageWriteSharp (>= 1.16.7)
-
net8.0
- AngleSharp (>= 1.6.0)
- DocumentFormat.OpenXml (>= 3.5.1)
- HtmlToOpenXml.dll (>= 3.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Win32.Registry (>= 5.0.0)
- OpenMcdf (>= 3.3.0)
- PdfPig (>= 0.1.16)
- Pdfxport.Net (= 7.0.6)
- Pdfxport.Net.MigraDoc (= 7.0.6)
- StbImageSharp (>= 2.30.16)
- StbImageWriteSharp (>= 1.16.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.4 | 88 | 11/6/2026 |
| 1.8.3 | 90 | 11/6/2026 |
| 1.8.2 | 336 | 11/1/2026 |
| 1.8.1 | 102 | 11/1/2026 |
| 1.8.0 | 95 | 11/1/2026 |
| 1.7.8 | 102 | 11/1/2026 |
| 1.7.7 | 153 | 10/12/2026 |
| 1.7.6 | 838 | 10/6/2026 |
| 1.7.5 | 101 | 10/6/2026 |
| 1.7.4 | 102 | 10/6/2026 |
| 1.7.3 | 120 | 10/6/2026 |
| 1.7.2 | 114 | 10/5/2026 |
| 1.7.1 | 533 | 9/29/2026 |
| 1.7.0 | 121 | 9/29/2026 |
| 1.6.4 | 2,083 | 9/9/2026 |
| 1.6.3 | 196 | 9/4/2026 |
| 1.6.2 | 524 | 9/2/2026 |
| 1.6.1 | 130 | 9/2/2026 |
| 1.6.0 | 163 | 9/1/2026 |
| 1.5.1 | 411 | 8/21/2026 |