PHPackages                             talleu/md-to-ooxml - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. talleu/md-to-ooxml

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

talleu/md-to-ooxml
==================

A lightweight PHP library to convert Markdown to Office Open XML (OOXML) and .docx files

v0.1.2(3mo ago)813↓90.9%MITPHPPHP &gt;=8.3CI passing

Since Mar 27Pushed 1mo agoCompare

[ Source](https://github.com/clementtalleu/md-to-ooxml)[ Packagist](https://packagist.org/packages/talleu/md-to-ooxml)[ Docs](https://github.com/clementtalleu/md-to-ooxml)[ RSS](/packages/talleu-md-to-ooxml/feed)WikiDiscussions main Synced 4w ago

READMEChangelog (1)Dependencies (4)Versions (7)Used By (0)

Markdown to OOXML
=================

[](#markdown-to-ooxml)

[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE)

A lightweight, extensible PHP library to convert Markdown into **Office Open XML (OOXML)** — the XML format used inside Microsoft Word `.docx` files.

Use it to:

- **Generate `.docx` files** directly from Markdown (with zero dependency on PHPWord or LibreOffice)
- **Get raw OOXML strings** to embed into existing documents
- **Inject Markdown content** into `.docx` templates

---

Features
--------

[](#features)

FeatureBuilt-in ParserCommonMark AdapterHeadings (H1–H6) with Word styles✅✅Paragraphs &amp; blank lines✅✅**Bold**, *italic*, ***bold+italic***✅✅**Underline**✅—Strikethrough✅✅`Inline code`✅✅Fenced code blocks (with language)✅✅Links✅✅Images (text placeholder)✅✅Bullet lists✅✅Ordered lists✅✅Blockquotes✅✅Horizontal rules✅✅Tables✅✅ (requires table extension)`.docx` file generation✅✅Template injection✅✅---

Requirements
------------

[](#requirements)

- PHP **8.3+**
- `ext-zip` (only required for `.docx` generation via `DocxWriter`)

Installation
------------

[](#installation)

```
composer require talleu/md-to-ooxml
```

### Optional: CommonMark support

[](#optional-commonmark-support)

```
composer require league/commonmark
```

---

Quick Start
-----------

[](#quick-start)

### 1. Markdown → OOXML string

[](#1-markdown--ooxml-string)

```
use Talleu\MdToOoxml\OoXmlConverterFactory;

$converter = OoXmlConverterFactory::create();

// Full document XML (document.xml content)
$xml = $converter->convert('# Hello **World**');

// Body fragment only (no XML declaration / envelope)
$bodyXml = $converter->convertToBodyXml('# Hello **World**');
```

### 2. Markdown → `.docx` file

[](#2-markdown--docx-file)

```
use Talleu\MdToOoxml\DocxWriter;

// One-liner: Markdown → .docx
DocxWriter::fromMarkdown('# My Document', '/path/to/output.docx');

// Or with a custom converter (e.g. CommonMark)
$converter = OoXmlConverterFactory::createWithCommonMark();
DocxWriter::fromMarkdown($markdown, '/path/to/output.docx', $converter);
```

### 3. Inject into an existing `.docx` template

[](#3-inject-into-an-existing-docx-template)

```
use Talleu\MdToOoxml\DocxWriter;
use Talleu\MdToOoxml\OoXmlConverterFactory;

$converter = OoXmlConverterFactory::create();
$bodyXml = $converter->convertToBodyXml('## New Section');

// Append content before
DocxWriter::injectIntoTemplate(
    templatePath: '/path/to/template.docx',
    bodyXml: $bodyXml,
    outputPath: '/path/to/output.docx',
);

// Or replace a placeholder string in the template
DocxWriter::injectIntoTemplate(
    templatePath: '/path/to/template.docx',
    bodyXml: $bodyXml,
    outputPath: '/path/to/output.docx',
    placeholder: '{{CONTENT}}',
);
```

### 4. Two-step: convert then save manually

[](#4-two-step-convert-then-save-manually)

```
use Talleu\MdToOoxml\OoXmlConverterFactory;
use Talleu\MdToOoxml\DocxWriter;

$converter = OoXmlConverterFactory::create();
$documentXml = $converter->convert($markdown);

// You can inspect/modify the XML here if needed
DocxWriter::save($documentXml, '/path/to/output.docx');
```

### 5. Render directly from an AST

[](#5-render-directly-from-an-ast)

If you already have a structured document (e.g. from your own parser, a CMS, or an API), you can skip the Markdown parsing step and pass an AST directly:

```
use Talleu\MdToOoxml\OoXmlConverterFactory;
use Talleu\MdToOoxml\Node\DocumentNode;
use Talleu\MdToOoxml\Node\ParagraphNode;
use Talleu\MdToOoxml\Node\TitleNode;
use Talleu\MdToOoxml\Node\TextRunNode;

$converter = OoXmlConverterFactory::create();

// Build the AST
$doc = new DocumentNode();

$title = new TitleNode(1);
$title->addChild(new TextRunNode('My Title'));
$doc->addChild($title);

$paragraph = new ParagraphNode();
$paragraph->addChild(new TextRunNode('Some text '));
$paragraph->addChild(new TextRunNode('in bold', isBold: true));
$doc->addChild($paragraph);

// Full document XML
$xml = $converter->renderDocument($doc);

// Or body fragment only
$bodyXml = $converter->renderToBodyXml($doc);
```

You can also get a standalone renderer without any parser dependency:

```
$renderer = OoXmlConverterFactory::createRenderer();
$xml = $renderer->render($doc);
```

See the [Node Types](#node-types) table below for all available nodes and their properties.

---

Parsers
-------

[](#parsers)

### Built-in Parser (zero dependencies)

[](#built-in-parser-zero-dependencies)

The default parser handles all common Markdown syntax via regex-based parsing. It's fast, lightweight, and requires no extra packages.

```
$converter = OoXmlConverterFactory::create();
```

> **Limitation:** The built-in parser does not support nested inline formatting. For example, `__some *italic* text__` will render the underline but treat the `*italic*` markers as literal text. If you need nested formatting (italic inside bold, underline inside strikethrough, etc.), use the CommonMark adapter below.

### League CommonMark Adapter

[](#league-commonmark-adapter)

For advanced Markdown features, use the adapter for [`league/commonmark`](https://commonmark.thephpleague.com/):

```
$converter = OoXmlConverterFactory::createWithCommonMark();
```

The adapter automatically enables the Table and Strikethrough extensions if available.

**Use the CommonMark adapter when you need:**

- Nested inline formatting (e.g. bold inside italic, italic inside underline)
- Strict [CommonMark](https://spec.commonmark.org/) compliance
- Edge cases the built-in regex parser may not handle correctly

### Custom Parser

[](#custom-parser)

Implement `MarkdownParserInterface` and inject it:

```
use Talleu\MdToOoxml\OoXmlConverterFactory;

$converter = OoXmlConverterFactory::createWithParser(new MyCustomParser());
```

---

Architecture
------------

[](#architecture)

```
Markdown string
    │
    ▼
┌──────────────────┐
│  Parser           │  BlockParser (built-in) or LeagueCommonMarkAdapter
│  (Markdown → AST) │
└──────────────────┘
    │
    ▼
┌──────────────────┐
│  AST (Node tree)  │  DocumentNode → ParagraphNode → TextRunNode, etc.
└──────────────────┘
    │
    ▼
┌──────────────────┐
│  Renderer         │  NodeRenderer dispatches to per-node RendererInterface
│  (AST → OOXML)    │
└──────────────────┘
    │
    ▼
  OOXML string
    │
    ▼ (optional)
┌──────────────────┐
│  DocxWriter       │  Packages XML into a valid .docx ZIP archive
└──────────────────┘

```

### Node Types

[](#node-types)

NodeDescription`DocumentNode`Root node`ParagraphNode`Paragraph`TitleNode`Heading (level 1–6)`TextRunNode`Inline text with formatting flags`InlineCodeNode`Inline code span`LinkNode`Hyperlink`ImageNode`Image reference`ListItemNode`Bullet or ordered list item`QuoteNode`Blockquote`CodeBlockNode`Fenced code block`BlankLineNode`Empty line`HorizontalRuleNode`Horizontal rule / thematic break`TableNode`Table (contains `TableRowNode` → `TableCellNode`)### Extending

[](#extending)

Register a custom renderer for any node type:

```
use Talleu\MdToOoxml\Renderer\NodeRenderer;
use Talleu\MdToOoxml\Renderer\RendererInterface;
use Talleu\MdToOoxml\Node\NodeInterface;

class MyCustomRenderer implements RendererInterface
{
    public function render(NodeInterface $node): string
    {
        // Return OOXML string
    }
}

// Get the factory-built converter and add your renderer
$converter = OoXmlConverterFactory::create();
// Or build the NodeRenderer manually for full control
```

---

Supported Markdown Syntax
-------------------------

[](#supported-markdown-syntax)

```
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

Regular paragraph text.

**Bold text** and *italic text* and ***bold italic***.

__Underlined text__ and ~~strikethrough~~.

`inline code`

[Link text](https://example.com)

![Image alt](https://example.com/image.png)

- Bullet item
- Another item
* Also bullet
+ Also bullet

1. Ordered item
2. Another item

> Blockquote text

---

| Column A | Column B |
| -------- | -------- |
| Cell 1   | Cell 2   |

\```php
echo "fenced code block";
\```
```

---

Testing
-------

[](#testing)

```
# Run all tests
vendor/bin/phpunit

# Run only unit tests
vendor/bin/phpunit --testsuite Unit

# Run only integration tests
vendor/bin/phpunit --testsuite Integration

# Run only functional tests (requires ext-zip)
vendor/bin/phpunit --testsuite Functional
```

---

How It Works (OOXML Primer)
---------------------------

[](#how-it-works-ooxml-primer)

A `.docx` file is a ZIP archive containing XML files. The main one is `word/document.xml`. This library generates valid OOXML that follows the [ECMA-376](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) specification.

The generated `.docx` includes:

FilePurpose`[Content_Types].xml`MIME type declarations`_rels/.rels`Package-level relationships`word/document.xml`The actual document content`word/_rels/document.xml.rels`Document-level relationships`word/numbering.xml`List (bullet/ordered) definitions`word/styles.xml`Heading and default styles---

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance88

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

3

Last Release

91d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/11056924?v=4)[Clément Talleu](/maintainers/clementtalleu)[@clementtalleu](https://github.com/clementtalleu)

---

Top Contributors

[![clementtalleu](https://avatars.githubusercontent.com/u/11056924?v=4)](https://github.com/clementtalleu "clementtalleu (10 commits)")

---

Tags

xmlconvertermarkdownworddocxOOXML

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/talleu-md-to-ooxml/health.svg)

```
[![Health](https://phpackages.com/badges/talleu-md-to-ooxml/health.svg)](https://phpackages.com/packages/talleu-md-to-ooxml)
```

###  Alternatives

[gotenberg/gotenberg-php

A PHP client for interacting with Gotenberg, a developer-friendly API for converting numerous document formats into PDF files, and more!

3845.9M27](/packages/gotenberg-gotenberg-php)[faisalman/simple-excel-php

Easily parse / convert / write between Microsoft Excel XML / CSV / TSV / HTML / JSON / etc formats

561606.4k1](/packages/faisalman-simple-excel-php)[mnvx/lowrapper

PHP wrapper over LibreOffice converter

127199.1k](/packages/mnvx-lowrapper)[aspose-cloud/aspose-words-cloud

Open, generate, edit, split, merge, compare and convert Word documents. Integrate Cloud API into your solutions to manipulate documents. Convert PDF to Word (DOC, DOCX, ODT, RTF and HTML) and in the opposite direction.

31169.4k](/packages/aspose-cloud-aspose-words-cloud)[paperdoc-dev/paperdoc-lib

A zero-dependency PHP library for generating, parsing and converting documents (PDF, HTML, CSV, DOCX)

1253.7k](/packages/paperdoc-dev-paperdoc-lib)[novay/laravel-word-template

Package Laravel untuk melakukan penggantian kata pada file menggunakan template dokumen (.doc atau .docx) yang sudah disediakan.

5515.9k](/packages/novay-laravel-word-template)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
