Создание Office-документов из Markdown
create_from_markdown создаёт новый DOCX, XLSX или PPTX из единственной строки Markdown. Один источник — три целевых формата. Markdown — естественный выход для контента, сгенерированного LLM: пусть модель выдаёт Markdown (это куда надёжнее, чем просить её напрямую генерировать Office XML), а затем преобразуйте его в нужный Office-формат по запросу.
Внутри Markdown разбирается в структурированный DocumentIR Office Oxide и рендерится в целевой формат, поэтому маппинг получается детерминированным и независимым от формата. IR сам по себе — это в первую очередь поверхность для извлечения и инспекции (см. to_ir()); для создания документов публичная точка входа во всех биндингах — Markdown.
Какова сигнатура create_from_markdown?
Функция принимает строку Markdown, целевой формат ("docx", "xlsx" или "pptx", регистр не важен) и путь для вывода. При успехе ничего не возвращает; при ошибке бросает исключение или возвращает ошибку.
| Биндинг | Сигнатура |
|---|---|
| Python | def create_from_markdown(markdown: str, format: str, path, /) -> None |
| Rust | pub fn create_from_markdown(markdown: &str, format: DocumentFormat, path: impl AsRef<Path>) -> Result<()> |
| Go | func CreateFromMarkdown(markdown, format, path string) error |
| JavaScript | createFromMarkdown(markdown, format, path) |
| C# | static void Document.CreateFromMarkdown(string markdown, string format, string path) |
Как создать DOCX, XLSX или PPTX из Markdown?
Напишите содержимое один раз в Markdown, а затем меняйте аргумент format, чтобы выбрать целевой формат.
Rust
use office_oxide::create::create_from_markdown;
use office_oxide::format::DocumentFormat;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let markdown = "\
# Quarterly Report
Generated automatically from Markdown using Office Oxide.
## Highlights
- Revenue grew by **32%** year-over-year
- Customer satisfaction: 4.8 / 5.0
## Financial Summary
| Category | Q3 2025 | Q4 2025 |
|------------|---------|---------|
| Revenue | $1.2M | $1.6M |
| Net Profit | $0.4M | $0.7M |
";
create_from_markdown(markdown, DocumentFormat::Docx, "report.docx")?;
create_from_markdown(markdown, DocumentFormat::Xlsx, "report.xlsx")?;
create_from_markdown(markdown, DocumentFormat::Pptx, "report.pptx")?;
Ok(())
}
Python
from office_oxide import create_from_markdown
markdown = """\
# Quarterly Report
Generated automatically from Markdown using Office Oxide.
## Highlights
- Revenue grew by **32%** year-over-year
- Customer satisfaction: 4.8 / 5.0
- New products launched: Widget Pro, Widget Lite
## Financial Summary
| Category | Q3 2025 | Q4 2025 |
|------------|---------|---------|
| Revenue | $1.2M | $1.6M |
| Expenses | $0.8M | $0.9M |
| Net Profit | $0.4M | $0.7M |
"""
# One Markdown source, three target formats:
create_from_markdown(markdown, "docx", "report.docx")
create_from_markdown(markdown, "xlsx", "report.xlsx")
create_from_markdown(markdown, "pptx", "report.pptx")
JavaScript
import { createFromMarkdown } from 'office-oxide';
const markdown = `# Quarterly Report
Generated automatically from Markdown using Office Oxide.
## Highlights
- Revenue grew by **32%** year-over-year
- Customer satisfaction: 4.8 / 5.0
## Financial Summary
| Category | Q3 2025 | Q4 2025 |
|------------|---------|---------|
| Revenue | $1.2M | $1.6M |
| Net Profit | $0.4M | $0.7M |
`;
for (const fmt of ['docx', 'xlsx', 'pptx']) {
createFromMarkdown(markdown, fmt, `report.${fmt}`);
}
Go
package main
import (
"log"
oo "github.com/yfedoseev/office_oxide/go"
)
func main() {
markdown := `# Quarterly Report
Generated automatically from Markdown using Office Oxide.
## Highlights
- Revenue grew by **32%** year-over-year
- Customer satisfaction: 4.8 / 5.0
## Financial Summary
| Category | Q3 2025 | Q4 2025 |
|------------|---------|---------|
| Revenue | $1.2M | $1.6M |
| Net Profit | $0.4M | $0.7M |
`
for _, fmt := range []string{"docx", "xlsx", "pptx"} {
if err := oo.CreateFromMarkdown(markdown, fmt, "report."+fmt); err != nil {
log.Fatalf("CreateFromMarkdown(%s): %v", fmt, err)
}
}
}
C#
using OfficeOxide;
const string markdown = """
# Quarterly Report
Generated automatically from Markdown using Office Oxide.
## Highlights
- Revenue grew by **32%** year-over-year
- Customer satisfaction: 4.8 / 5.0
## Financial Summary
| Category | Q3 2025 | Q4 2025 |
|------------|---------|---------|
| Revenue | $1.2M | $1.6M |
| Net Profit | $0.4M | $0.7M |
""";
foreach (var fmt in new[] { "docx", "xlsx", "pptx" })
{
Document.CreateFromMarkdown(markdown, fmt, $"report.{fmt}");
}
C
#include <stdio.h>
#include "office_oxide.h"
int main(void) {
const char *markdown =
"# Quarterly Report\n\n"
"Generated automatically from Markdown using Office Oxide.\n\n"
"## Highlights\n\n"
"- Revenue grew by **32%** year-over-year\n"
"- Customer satisfaction: 4.8 / 5.0\n\n"
"## Financial Summary\n\n"
"| Category | Q3 2025 | Q4 2025 |\n"
"|------------|---------|---------|\n"
"| Revenue | $1.2M | $1.6M |\n"
"| Net Profit | $0.4M | $0.7M |\n";
/* format: "docx" | "xlsx" | "pptx" (case-insensitive) */
const char *formats[] = { "docx", "xlsx", "pptx" };
for (int i = 0; i < 3; i++) {
int err = 0;
char path[32];
snprintf(path, sizeof(path), "report.%s", formats[i]);
if (office_create_from_markdown(markdown, formats[i], path, &err) != 0) {
fprintf(stderr, "create_from_markdown(%s) failed: code=%d\n", formats[i], err);
return 1;
}
}
return 0;
}
Как Markdown рендерится в каждый целевой формат?
Markdown разбирается в структурированный IR Office Oxide, а затем каждый формат детерминированно рендерит эту структуру:
| Конструкция Markdown | DOCX | XLSX | PPTX |
|---|---|---|---|
Заголовок # |
Абзац со стилем Heading{level} |
Жирная ячейка в начале раздела | Заполнитель заголовка слайда |
| Текст абзаца | Текстовый абзац | Ячейки в последовательных строках | Заполнитель основного текста |
Список - / 1. |
Маркированный или нумерованный список | Ячейки в столбце A | Маркеры основного текста |
| Таблица | Таблица Word | Ячейки начиная со следующей свободной строки | Таблица PowerPoint |
**жирный** / *курсив* |
Форматирование встроенного текста | Простой текст ячейки | Форматирование встроенного текста |
Маппинг намеренно консервативен: каждая конструкция Markdown даёт детерминированный результат, однако в каждом формате есть возможности, которые Markdown не моделирует (числовые форматы ячеек XLSX, анимации PPTX, цепочки комментариев DOCX). Для более богатого вывода создайте файл, а затем отредактируйте его в редакторе конкретного формата или воспользуйтесь специализированными писателями.
Как читать, изменять и записывать обратно между форматами?
Комбинируйте извлечение и создание, чтобы редактировать содержимое с сохранением работоспособности в разных форматах. Читайте источник как Markdown, вносите правки и записывайте новый файл:
Python
from office_oxide import Document, create_from_markdown
with Document.open("legacy.doc") as doc:
markdown = doc.to_markdown()
# Append a new section
markdown += "\n## Appendix\n\nEffective 2026-06-22.\n"
create_from_markdown(markdown, "docx", "modernized.docx")
C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "office_oxide.h"
int main(void) {
int err = 0;
/* Read the source as Markdown */
OfficeDocumentHandle *doc = office_document_open("legacy.doc", &err);
if (!doc) { fprintf(stderr, "open failed: code=%d\n", err); return 1; }
char *md = office_document_to_markdown(doc, &err);
office_document_free(doc);
if (!md) { fprintf(stderr, "to_markdown failed: code=%d\n", err); return 1; }
/* Append a new section */
const char *appendix = "\n## Appendix\n\nEffective 2026-06-22.\n";
char *modified = malloc(strlen(md) + strlen(appendix) + 1);
strcpy(modified, md);
strcat(modified, appendix);
office_oxide_free_string(md);
/* Write a fresh file */
office_create_from_markdown(modified, "docx", "modernized.docx", &err);
free(modified);
return err;
}
Это также чистый путь для модернизации устаревших форматов в OOXML (DOC → DOCX, XLS → XLSX, PPT → PPTX), когда нужна только текстовая структура. Для конвертации с сохранением оригинальной разметки используйте save_as() — он делает полный обход через IR. См. Конвертация: устаревшие форматы → OOXML.
Зачем генерировать Office-файлы из Markdown?
- Независимые от формата шаблоны. Генерируйте один и тот же контент в виде DOCX (для пользователей Word), XLSX (для аналитиков) или PPTX (для презентаций) без переписывания — просто меняйте аргумент
format. - Нативно для LLM. Пусть модель выдаёт Markdown, а вы материализуете файл. Markdown — то, что модели генерируют наиболее надёжно.
- Поддерживает диффы. Markdown — это обычный текст; его можно коммитить. Office-файл становится артефактом сборки.
- Быстро. Rust-ядро Office Oxide записывает файлы за миллисекунды с показателем прохождения 100% на корпусе бенчмарков.
Продвинутый уровень: сборка напрямую из DocumentIR (Rust)
Rust-крейт дополнительно предоставляет create_from_ir для тех, кто хочет вручную строить или преобразовывать структурированный IR вместо работы через Markdown:
use office_oxide::create::create_from_ir;
use office_oxide::format::DocumentFormat;
use office_oxide::ir::DocumentIR;
// Build or transform a DocumentIR however you like, then render it:
let ir: DocumentIR = DocumentIR::from_markdown("# Title\n\nBody.\n", DocumentFormat::Docx);
create_from_ir(&ir, DocumentFormat::Docx, "report.docx")?;
pub fn create_from_ir(ir: &DocumentIR, format: DocumentFormat, path: impl AsRef<Path>) -> Result<()>
В биндингах Python, Go, JavaScript и C# IR доступен только для чтения — получайте его через to_ir() для инспекции и пайплайнов, а файлы создавайте с помощью create_from_markdown.
Ограничения
- Форматирование ячеек (числовые форматы, валюты, пользовательские стили) в Markdown не выражается. Добавляйте его через редактор конкретного формата после создания.
- Изображения, диаграммы, SmartArt и встроенные объекты через путь Markdown не передаются — используйте специализированные писатели (
XlsxWriter,PptxWriterили DOCX-строитель). - Объединение ячеек XLSX, анимации PPTX и цепочки комментариев DOCX не имеют аналогов в Markdown.
Для всего, что выходит за пределы выразительных возможностей Markdown, используйте специализированные писатели для каждого формата. Они дают полный доступ к возможностям OOXML, но привязаны к конкретному формату.
Часто задаваемые вопросы
Какие форматы может генерировать create_from_markdown?
DOCX, XLSX и PPTX. Аргумент format принимает значения "docx", "xlsx" или "pptx" (регистр не важен). Устаревшие бинарные форматы (DOC, XLS, PPT) доступны только для чтения и не могут быть созданы.
Есть ли функция create_from_ir в Python или других биндингах?
Нет. create_from_ir доступна только в Rust-крейте. В Python, Go, JavaScript и C# создавайте файлы с помощью create_from_markdown; IR (to_ir/to_ir_json) — это концепция на стороне извлечения, доступная только для чтения.
Как сделать полный обход существующего документа с сохранением разметки?
Используйте save_as() для конвертации с сохранением структуры. Используйте to_markdown() + create_from_markdown(), когда вам нужно чисто восстановить только текстовую структуру.
Насколько быстро происходит создание документов? Rust-ядро Office Oxide записывает Office-файлы за миллисекунды с показателем прохождения 100% на корпусе бенчмарков — достаточно быстро, чтобы генерировать документы по запросу прямо внутри обработчика запросов.
Смотрите также
- Структурированный IR — подробное описание схемы IR (сторона извлечения)
- Конвертация: устаревшие форматы → OOXML — модернизация DOC/XLS/PPT
- Обзор редактирования — изменение существующих файлов на месте