Automate Invoice Processing with an AI Agent in .NET

Automated invoice processing means reading incoming vendor invoices, extracting line items, validating them against purchase orders, and writing the results into a structured workbook your finance system can consume. In practice, this is document automation in .NET where a natural-language instruction replaces the field-mapping and layout code. Spire.Agent.Office is a document AI agent SDK that handles the language; a deterministic document layer guarantees real, well-formed Excel and PDF files.
Quick Navigation
- Why Invoice Processing Is a Good Fit for AI
- What an AI Invoice Agent Can and Cannot Do
- Common Invoice Processing Scenarios
- Three Ways to Automate Invoice Processing in .NET
- A Working Example: Extract, Validate, and Report in C#
- Why Use Spire.Agent.Office for AI Invoice Processing
- FAQ
1. Why Invoice Processing Is a Good Fit for AI
Invoice work in a developer's world is three repetitive jobs: reading (extracting vendor, date, line items, and totals from documents that arrive as PDFs, Word files, Excel sheets, or scanned images), checking (matching invoices against purchase orders and flagging discrepancies), and producing (writing the results into a structured workbook your accounting system can consume).
For .NET developers, the challenge is not only understanding invoice content; it is turning unstructured, multi-format documents into structured, repeatable workflows your application can own.
Three properties make these tasks ideal for a language model rather than hand-written rules:
- The input is multi-format. Incoming invoices arrive as PDF attachments, scanned images, Word documents, or Excel files — each with a different layout. Rules that handle one format break on the next; an LLM reads text directly regardless of file type.
- The output is document-shaped. The deliverable is a real
.xlsxor.pdfwith correct formatting, not a text blob. This is where a document layer earns its keep. - The volume changes constantly. Onboarding 50 new suppliers or reviewing 200 vendor invoices in a month means a config-driven solution, not re-coding per supplier.
In practice, extraction and validation go together: teams want invoices summarized and discrepancies flagged, and new invoices generated from a template plus structured data. For a deeper look at how a document AI agent is put together and where it fits in a content pipeline, see AI Agent for Document Processing: What It Is and How It Works.
2. What an AI Invoice Agent Can and Cannot Do
| Can do | Cannot do |
|---|---|
| Extract vendor, date, line items, totals from PDF, Word, Excel, and scanned images | Replace professional AP review for high-value or regulated transactions |
| Match invoices against purchase orders and flag discrepancies | Guarantee matching accuracy on intentionally ambiguous or fraudulent invoices |
| Generate structured workbooks or PDF reports in batch | Negotiate or accept terms on your behalf |
| Keep formatting, table styles, and fonts intact | Interpret new or ambiguous supplier terms; route to procurement |
| Run inside your own application (no cloud upload) | Guarantee output is error-free without review |
The division of labor: the agent automates the reading, extraction, and validation (the hours an AP clerk would spend), while a human reviewer owns the final sign-off. That boundary is what keeps the tool useful and the process defensible.
3. Common Invoice Processing Scenarios
Invoice processing spans more than one-off extraction. The same pattern (an instruction, invoice files, and optional reference data) covers the scenarios teams search for most:
| Scenario | Example instruction |
|---|---|
| Multi-format invoice extraction | "Extract vendor, date, line items, and totals from these invoices and merge into one worksheet." |
| PO three-way matching | "Compare each invoice against purchase orders and flag discrepancies over 5%." |
| Batch invoice reporting | "Generate a summary workbook with total amount by supplier, flagged discrepancies, and a printable report." |
| Duplicate detection | "Identify potential duplicate invoices by comparing vendor, date, and amount across the inbox." |
| Approval workflow routing | "Route invoices above $10,000 to the approval queue and below to auto-approve." |
Each scenario is the same architecture: an instruction in, a real document out.
4. Three Ways to Automate Invoice Processing in .NET
| Approach | Code volume | Format fidelity | Maintenance | Best for |
|---|---|---|---|---|
| Document AI agent (LLM + document layer) | One instruction + ~10 lines | High (real Excel/PDF files) | Low (change behavior by editing instructions) | Teams automating invoices without building an LLM pipeline |
| Raw LLM API (OpenAI/Claude + your own code) | High (prompts, parsing, file I/O) | Low (LLMs don't natively read/write Office files) | High (you own RAG, routing, errors) | Teams that already run an LLM stack |
| Traditional SDK (Spire.Office or similar) | Dozens of lines per document type | High (deterministic) | High (every mapping is code) | Fixed, well-specified invoices that rarely change |
The key point: an LLM cannot read a PDF invoice without a document-processing layer, and a traditional SDK cannot understand a natural-language request. A document AI agent combines both.
That is not to say the traditional route is wrong. For fixed, well-specified invoices that rarely change, a deterministic SDK is often the right call, and Spire.Office still serves that need. If that is your situation, Generate Word Documents from Excel Data in C# demonstrates the classic data-driven document generation workflow. The agent earns its place when supplier layouts, input formats, and validation rules change often enough that re-coding becomes the bottleneck.
Why a Raw LLM API Is Not Enough for Invoice Processing
Calling gpt-4 or claude directly to "extract data from this invoice" fails in three ways that matter in production:
- It cannot reliably read or write Office files. LLMs see text, not
.xlsxand.pdfstructure. Reading a PDF invoice, keeping a line-item table intact, or producing a valid Excel workbook usually requires a separate extraction and reconstruction pipeline you have to build yourself. - Formatting is not guaranteed. Invoice reports carry column headers, number formats, and conditional fills that matter to the accounting team. A raw LLM returns text, and the formatting you lose is exactly what AP departments care about.
- You reimplement the whole orchestration. Prompt design, field mapping, error handling, file I/O, and output validation become your code to own and maintain.
A document AI agent pairs the model's language understanding with deterministic document APIs: the model decides what to extract or match, and the document layer guarantees the file is real and well-formed. That is the difference between a demo and a workflow a team can ship.
5. A Working Example: Extract, Validate, and Report in C#
Below is a task the AP team repeats every month: processing incoming vendor invoices, extracting data from mismatched formats, validating against purchase orders, and producing a structured workbook. The implementation uses Spire.Agent.Office for .NET, an AI agent that processes Word, Excel, PowerPoint, and PDF documents through natural-language instructions. The example is designed around that workflow rather than copied from a tutorial; the official Getting Started and AI Contract Review in C# tutorials document the API setup step by step, while this section focuses on the C# integration patterns.

1. Extract data from every invoice in the inbox. Configure the agent once, then read the inbox folder and have each invoice parsed into a single merged table:
using System.IO;
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;
using Spire.Pdf;
using Spire.Xls;
AIOptions agentOptions = new AIOptions();
agentOptions.WorkDir = @"C:\ap-invoices\output";
agentOptions.SpireToken = spireToken;
string extractPrompt =
"Read every vendor invoice file in the inbox (PDF, Word, Excel, or images) and extract " +
"each supplier's information: company name, invoice number, issue date, due date, line " +
"items (description, quantity, unit price, amount), subtotal, tax, and total. Merge the " +
"results into one worksheet with columns: Supplier, InvoiceNumber, IssueDate, DueDate, " +
"Description, Quantity, UnitPrice, LineAmount, Subtotal, Tax, Total. Skip duplicate header " +
"rows and save as a workbook.";
Directory.CreateDirectory(@"C:\ap-invoices\output");
string[] invoiceFiles = Directory.GetFiles(@"C:\ap-invoices\inbox", "*.*");
The agent handles the multi-format challenge — PDFs, scanned images, Word documents, and Excel files all flow through the same instruction without format-specific code:
using (Workbook extracted = new Workbook())
{
AIResult result = extracted.AI(agentOptions).ExecuteInstruction(
extracted,
extractPrompt,
@"C:\ap-invoices\output\extracted.xlsx",
invoiceFiles);
if (result == null || !result.Success)
throw new InvalidOperationException(
$"Extraction failed: {result?.ErrorMessage}");
}
Key API Calls
Workbook.AI(agentOptions)— attaches the AI document processor to a workbook objectExecuteInstruction(doc, instruction, savePath, attachments)— runs the extraction and writes the merged workbookAIResult.Success/AIResult.ErrorMessage— verifies the result and surfaces errors
Output

2. Validate against purchase orders. Load the extracted file and state the matching rule in plain English. The agent adds a Validation sheet and leaves the source data untouched:
using (Workbook validation = new Workbook())
{
validation.LoadFromFile(@"C:\ap-invoices\output\extracted.xlsx");
string[] poFiles = { @"C:\ap-invoices\data\purchase-orders.xlsx" };
AIResult result = validation.AI(agentOptions).ExecuteInstruction(
validation,
"Add a 'Validation' sheet. Compare each invoice line item against the purchase orders " +
"in the attachments, flag invoices where the total differs from the PO by more than 5%, " +
"flag line items whose description does not match the PO. Highlight discrepancies in red " +
"and add a 'Reason' column explaining each discrepancy. Leave the original data sheets unchanged.",
@"C:\ap-invoices\output\validated.xlsx",
poFiles);
if (result == null || !result.Success)
throw new InvalidOperationException(
$"Validation failed: {result?.ErrorMessage}");
}
The Validation sheet lands alongside the source data, with the flagged rows, red fills, and Reason column applied by the instruction:

3. Report. Compose the summary from section 5 and export it. The savePath alone chooses the format — .xlsx here, .pdf for distribution:
using (Workbook report = new Workbook())
{
report.LoadFromFile(@"C:\ap-invoices\output\validated.xlsx");
AIResult result = report.AI(agentOptions).ExecuteInstruction(
report,
"Produce a processing report. Add a 'Summary' sheet at the front with a KPI block " +
"(total invoices processed, total amount, count of flagged discrepancies, top supplier by " +
"volume), a detail table grouped by supplier, and a discrepancy summary. Format it for print " +
"and save the finished workbook.",
@"C:\ap-invoices\output\monthly-report.xlsx");
if (result == null || !result.Success)
throw new InvalidOperationException(
$"Report generation failed: {result?.ErrorMessage}");
}
The Summary sheet lands at the front of the workbook, ready for print or PDF export:

Why This Is Different: Traditional SDK vs. AI Agent
The value of the agent is clearest side by side. With the traditional SDK you locate each field by header string, hardcode every validation threshold, and write every cell by cell — and re-tune all of it when a supplier changes their layout or the rule changes. The sketch below (simplified for illustration) shows the shape of that work:
// Traditional SDK (illustrative): every field is located and extracted
// by header string, thresholds are hardcoded, and output is written cell by cell
foreach (string file in invoiceFiles)
{
Workbook wb = new Workbook();
wb.LoadFromFile(file);
Worksheet sheet = wb.Worksheets[0];
// Fails the moment a supplier changes "Total Due" to "Amount Payable".
int totalCol = FindColumnByHeader(sheet, "Total Due");
int vendorCol = FindColumnByHeader(sheet, "Vendor Name");
for (int r = sheet.LastRow; r >= 2; r--)
{
double invoiceTotal = double.Parse(sheet.Range[r, totalCol].Text);
double poTotal = GetPoTotal(sheet.Range[r, 1].Text);
double diff = Math.Abs(invoiceTotal - poTotal) / poTotal;
// One hardcoded threshold; a construction supplier triggers false alarms.
if (diff > 0.05) sheet.Range[r, totalCol].Style.Color = Color.Red;
}
// ... then merge, then validate, then summary -- hundreds of lines per supplier and per month.
}
The AI agent replaces that orchestration with one instruction:
validation.AI(agentOptions).ExecuteInstruction(
validation,
"Add a 'Validation' sheet. Compare each invoice line item against the purchase orders " +
"in the attachments, flag invoices where the total differs from the PO by more than 5%, " +
"flag line items whose description does not match the PO. Highlight discrepancies in red " +
"and add a 'Reason' column explaining each discrepancy. Leave the original data sheets unchanged.",
@"C:\ap-invoices\output\validated.xlsx",
poFiles);
Both produce the same validation workbook. Where the SDK grows a FindColumnByHeader call for every field, a threshold comparison for every rule, and a cell write for every fill, the agent absorbs the same work into one instruction. When a supplier changes their layout or the finance team changes the variance threshold, you edit the instruction, not the code.
6. Why Use Spire.Agent.Office for AI Invoice Processing
The three-way comparison above is deliberately product-neutral; the same pattern works with any capable LLM. Where Spire.Agent.Office earns its place for .NET teams is in three specific areas:
- Native multi-format invoice processing. PDFs, Word documents, Excel files, and scanned images are first-class citizens, not formats you bolt on. The agent reads and extracts from all four formats in a single instruction.
- Formatting is preserved. Invoice reports carry column headers, number formats, and conditional fills that must survive processing. The agent's document layer keeps them intact. Include "preserve the original document layout and styling" in your instruction and the output stays true to the template.
- Native .NET integration. It is a C# SDK that drops into an existing .NET application. No separate document-processing service to build or maintain, no cross-service plumbing. The example above is the whole integration surface.
If you already run Spire.Office for document processing, the agent is the natural next layer: the same Workbook object gains an AI() processor that turns instructions into executed workflows.
7. FAQ
Can AI invoice processing work with scanned images?
Yes. The extraction example above loads scanned image files alongside PDFs and Word documents, and the agent reads and analyzes each file in its native format. For scanned images with no extractable text layer, the agent works with the image content directly. If the scan quality is poor, consider running OCR first for best results.
Can invoice data stay inside my environment?
Yes, with one important nuance. Spire.Agent.Office runs from your own application, so the SDK, templates, and document processing stay inside your environment. Invoice files are not uploaded to a third-party document service for storage or conversion. To analyze invoice content, the AI needs the relevant text, and it is sent to the model for processing; that is an inherent step of any AI workflow. If you deploy your own model on your local network, the content stays entirely within your infrastructure. If you connect through a hosted model API such as OpenAI or Azure OpenAI, the relevant content is transmitted to that provider over the network per your configuration.
Can I use my own AI model with Spire.Agent.Office?
Yes. Spire.Agent.Office supports flexible AI model integration and is compatible with mainstream AI infrastructure, including hosted model APIs and privately deployed models. You can point the agent at your own endpoint. See the integration tutorial for setup details; for questions about which providers are supported in your deployment, contact your account team at sales@e-iceblue.com.
Which model does Spire.Agent.Office use for invoice processing?
Spire.Agent.Office connects to a large language model behind a SpireToken key. You describe the extraction or validation task in natural language, and the agent orchestrates the underlying document-processing tools. The model handles understanding; the document layer guarantees formatting and file fidelity.
Can it process invoices in batch?
Yes. One instruction applied to a folder of invoice files, and the agent produces one consolidated workbook with all extracted data. Both field extraction and cross-document matching are supported. For the agent to pick up every invoice, keep the inbox folder organized and avoid blank files; if the number of processed invoices does not match the inbox count, check the data source first.
Will the AI change my workbook's formatting?
Not if you say so. Include a phrase like "preserve the original document layout, styling, and fonts" in your instruction; the official tutorial documents this exact fix.
How is this different from using a raw LLM API?
A raw LLM cannot reliably read, edit, or write Word and Excel files on its own; it needs a document-processing layer. A document AI agent pairs the LLM's language understanding with deterministic document APIs, so the output is a real, well-formed file.
Ready to Automate Your Invoice Processing?
Extraction, validation, and report composition are the fastest places to get value: point the agent at the inbox, describe the processing rules, and get a structured workbook or PDF out. Follow the Getting Started tutorial to run your first invoice workflow in .NET.
Further Reading
- Spire.Agent.Office product overview -- AI agent SDKs for every Office document format
- AI Agent for Document Processing: What It Is and How It Works -- the document AI agent concept explained
- Generate Word Documents from Excel Data in C# -- data-driven document generation with the deterministic SDK
- AI Contract Review in C# -- the same agent workflow applied to Word and PDF documents
Generate Word Documents from Excel Data in C#

Generate Word documents from Excel data means using spreadsheet rows as the source for one or more structured Word files, usually by following a template or a document-generation workflow. Traditionally this job is handled with Word Mail Merge: you map Excel columns to fields in a .docx template and let Word emit one document per row. The same task can be automated in C# with a document SDK, or pushed further with an AI document agent that carries the requirement as a natural-language instruction. This article compares the routes, shows where mail merge stops coping, and walks a working C# example built on Spire.Agent.Office, an AI agent SDK for Office documents.
Quick Navigation
- What Does It Mean to Generate Word Documents from Excel?
- Mail Merge from Excel to Word
- Three Ways to Automate Word Generation from Excel in .NET
- Generate Personalized Word Documents from Excel in C#
- FAQ
1. What Does It Mean to Generate Word Documents from Excel Data?
The phrase sounds close to "convert Excel to Word," but the intent is different. Converting .xlsx to .docx changes a file's format and keeps its content roughly the same. Generating Word documents from Excel data builds new documents whose content is derived from cells in a spreadsheet: an order sheet per customer, a monthly report per region, a batch of letters or labels from an address list, a set of invoices from an orders sheet.
The recurring shape of the requirement is nearly always the same:

Sent as a real sentence it sounds like: "I have a list of customers and their orders in Excel; I need a Word document for each one with their information, their items, and a total." The word that matters is derived: the document content comes from data, so this is data-to-document generation, not a format switch.
That is the demand this article targets. Everything below is about the different ways to satisfy it and the point at which you should stop wiring fields by hand.
2. The Traditional Way: Mail Merge from Excel to Word
At the UI level, the default answer to "turn this Excel list into many Word documents" is Word Mail Merge. It is the feature most people are thinking of when they search for the task, and Microsoft ships a click-by-click guide for it. The mechanism is simple and well understood:

You place a field like «CustomerName» inside a letter template, bind it to the Customer column of the Excel source, run the merge, and Word writes one document per row with that value substituted. Because the row count can be thousands, it turns "open a file, copy the text, change the name" into a batch operation with zero code.
Mail merge is good at exactly one shape of work: put this column into that field, many times. Letters, envelopes, labels, and notices with a fixed layout are its home turf. It runs inside Office, needs no programming, and for those stable, field-only documents it is genuinely the right tool.
3. When Mail Merge Hits Its Limits
The limit arrives the moment the document stops being a fixed form with blank spots and becomes something that must depend on the data. Mail merge substitutes values; it does not decide structure, reason about content, or compose anything new.
Compare two requests. The first is what mail merge handles:
"Put the customer's name in the name spot, the address in the address spot, and the order into the order details."
The second is the request most real reporting turns out to be:
"Read this Excel workbook, analyze each customer's data, create a personalized report with their items and totals, add a summary of their buying pattern, and save each result as a separate Word document."
The second request fails on all three of mail merge's assumptions:
- The structure varies. A customer with three line items needs a different document body than one with thirty. Merge fields assume a fixed layout with fixed blanks; they do not grow a table by as many rows as the data requires.
- Content must be computed, not copied. "Summarize the buying pattern" and "flag high-value customers" produce text and decisions that no column holds. There is no source field to bind them to.
- The output is a batch of real files. Each record should be its own Word document with its own name, and the workflow should run unattended inside an application, not from an Office wizard.
That is the honest position of mail merge, stated fairly: it is excellent at field mapping, but it becomes less suitable when document structure, content, or output logic must vary with the data. The deeper requirement -- turn data into documents -- is a generation problem, and it is where the automation routes below start.
4. Turn the Requirement into an Instruction: the Agent Way
The alternative that fits the correct version of the problem is an AI document agent: a natural-language layer on top of a deterministic document engine. Instead of enumerating template fields and per-field code, you describe the output, and the agent can handle requirements that are difficult to express with traditional mail merge -- reading the data, shaping the structure, writing the analysis -- while the document engine guarantees a real, well-formed .docx (or PDF) comes out.
The value is easier to see as a chain:

Steps that are difficult to express with traditional mail merge -- especially the middle three -- are exactly where an agent can earn its keep. It can interpret what a column means ("Total Amount," "Sales," and "Net" can name the same concept under three headers), shape a document structure to each record, and compose the summary paragraphs. What you provide is a sentence, not a field map.
The message to carry into the rest of this article: mail merge maps Excel columns to Word fields; an AI agent generates documents from a requirement. The former is a value-substitution step, the latter is what the request actually was.
5. Three Ways to Automate Word Generation from Excel in .NET
Settling on the right route matters more than the code, because each route has a different cost curve. For a .NET application that needs this workflow, the realistic choices are:
| Approach | What it takes | Flexibility | Best for |
|---|---|---|---|
| Word Mail Merge | A .docx template with merge fields + an Excel source; run the merge (or script it) | Maps one column to one field; stalls on variable structure, conditional content, analysis | Letters, labels, envelopes, notices with a fixed shape |
| SDK field binding | Load the template in code, open the workbook, loop rows, bind/find-replace per record, save each file | Deterministic and testable; you hand-maintain the column map and layout, every change recompiles | Repeating one stable document shape at scale |
| Natural-language AI agent | Pass the workbook as an attachment, describe the output, read the result | Handles variable structure, per-record analysis, conditional sections, summaries | Documents that vary with the data, or workflows that change month to month |
A shortcut that decides most cases:
- Shape never changes, one field per column, bulk letters -- mail merge is hard to beat.
- Shape never changes but you need it in code, deterministic and testable -- use an SDK field-binding loop.
- The document must vary with the data, include analysis, or change often -- that is where an AI agent pays for itself, because the cost of a change can often be reduced to updating the instruction rather than changing the mapping and layout logic in code.
6. Generate Personalized Word Documents from Excel in C#
A concrete, working version of the "one Word document per record" requirement is a customer order summary. The inputs are a workbook of customer orders and a light Word template; the output is one personalized document per customer. The full setup -- token, package, and project wiring -- is documented in the Getting Started tutorial; here we focus on the generation call itself.
using Spire.Doc;
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
AIOptions options = new AIOptions
{
SpireToken = spireToken,
WorkDir = @"C:\order-ops\output", // folder the generated documents are written to
TimeoutMs = 300000
};
using (Document doc = new Document())
{
// The template supplies per-record anchors; the workbook is the data source.
doc.LoadFromFile(@"C:\order-ops\templates\order-summary-template.docx");
// savePath = null: one instruction produces one document per record,
// written into the WorkDir output folder. No C# loop over the rows.
AIResult result = doc.AI(options).ExecuteInstruction(
doc,
"Read the customer order data in Q3-orders.xlsx. Generate one independent " +
"Word order summary per customer, row by row. Include their contact " +
"information, every line item with quantity and amount, the order totals, " +
"and a one-paragraph summary of their purchasing pattern. Flag customers " +
"whose total exceeds 50,000 as high-value. Save each document as its own " +
"file named output_ followed by the customer's name (for example " +
"output_acme-order-summary.docx).",
null,
new[] { @"C:\order-ops\input\Q3-orders.xlsx" });
if (result == null || !result.Success)
throw new InvalidOperationException($"Generation failed: {result?.ErrorMessage}");
}
Three details matter when you run this yourself. First, the instruction is where the generation logic lives: the analysis ("summary of their purchasing pattern"), the conditional logic ("flag customers above 50,000"), and the per-record structure ("every line item"). Second, the workbook should be tidy: first row is the header, one record per row, no empty rows or merged header cells -- the same rules Word's own data source expects. Third, the base document anchors the output layout; a lightly structured one can give the agent a useful starting point for the structure of each record. With a fully empty base document, the same instruction produces a single composed document instead.
A naming rule matters here: documents the agent writes into WorkDir must start with the output_ prefix, or the SDK does not count them as generated files. That is why the instruction above asks for files like output_acme-order-summary.docx instead of bare customer names.

The .docx extension on your save target or file pattern picks the output format; point the same instruction at .pdf and the agent exports the identical documents for distribution, with no separate rendering step.
Key API Calls
Document.AI(options)-- attaches the AI document processor to a Word document objectExecuteInstruction(doc, instruction, savePath, attachments)-- runs the generation;nullsavePath means "write intoWorkDir", and the workbook rides along inattachmentPathsAIResult.Success/AIResult.ErrorMessage-- verifies the run and surfaces failures
7. What You Would Write Without an Agent
For contrast, the SDK-field-binding route for the same job does everything explicitly. The following is intentionally simplified to show the amount of application logic involved; a production implementation would also need to load and group the workbook data:
using Spire.Doc;
using Spire.Xls;
// A fixed shape is fine; every variation is more wiring.
foreach (DataRow row in customersTable.Rows)
{
using (Document doc = new Document())
{
doc.LoadFromFile(@"templates\order-summary-template.docx");
// Find-and-replace per anchor...
doc.Replace("{{CustomerName}}", row["Customer"].ToString(), true, true);
doc.Replace("{{TotalAmount}}", row["Amount"].ToString("C"), true, true);
// Line items live in a second sheet: you hand-join them per customer,
// build a table, and insert it at a bookmark...
// The "flag high-value customers" rule is an if/else you maintain,
// and the per-customer summary paragraph is a template you write by hand.
doc.SaveToFile($@"out\{row["Customer"]}-order-summary.docx");
}
// ... and every new rule, column, or layout change means editing this and recompiling.
}

The agent does not remove the need for code -- it removes the need for mapping and layout code. The difference is where the logic lives: in a column index and a find-and-replace, or in a sentence the business can read and edit. When business rules or document structures change frequently, the natural-language approach can reduce the amount of mapping and layout code that must be maintained. The template-plus-data pattern scales beyond order summaries: Batch Contract Generation with Spire.Agent.Office walks the same one-instruction, one-document-per-record flow applied to contracts.
8. Where AI Stops and Application Logic Begins
A useful boundary is not "what AI can and cannot do" but what the application should keep owning. A document generation agent sits on top of deterministic code; it does not replace it.
Your application still owns the parts that have nothing to do with understanding the spreadsheet:
- File discovery and access -- finding the workbook, checking permissions, staging inputs
- Workflow scheduling -- when the job runs, on what trigger, in what order
- Data source control -- which workbook is an authorized input and where it came from
- Error handling and retries -- what happens when a file is missing or a run fails
- Final approval -- a human reviews the generated documents before they ship
The agent handles the semantic steps:
- Understanding -- reading what each column means from different workbooks
- Planning structure -- determining how many sections and rows the document needs
- Analysis -- turning order data into a summary and a high-value flag
- Composition -- assembling personalized Word documents from the requirement
Keep the deterministic plumbing in code, where it is testable and auditable, and hand the semantic generation to the agent. Each side does what it is good at. AI Contract Review in C# shows the same split from the other side: the agent handles the semantic step of reviewing a document's content while the application keeps the deterministic file handling around it.
9. FAQ
Is this a replacement for Word mail merge?
Not a drop-in replacement; it is the same job taken further. Mail merge maps Excel columns into fixed Word fields, which is enough for a letter with a stable shape. An AI agent can do that too, and can also read the workbook by content, shape structure per record, add analysis, and compose prose. For simple fixed-shape outputs, mail merge stays a fine tool; when the document must vary with the data, the agent carries more of the work.
How do I generate multiple Word documents from Excel data?
Pass the workbook as an attachment, set the save path to null, and point AIOptions.WorkDir at an output folder. One ExecuteInstruction with a row-by-row instruction makes the agent produce one independent document per record, each saved to that folder. No C# loop over the rows is needed for the per-record batch.
Can I generate Word documents from Excel without using Mail Merge?
Yes. In C# you can bind a template with the SDK directly, or hand the workbook to an AI agent that reads it from a natural-language instruction, and receive a real .docx or PDF in return. Mail merge is one route, not the only route, and it is the least flexible once the document needs analysis or conditional sections.
What is the difference between Mail Merge and AI document generation?
Mail merge binds defined fields to defined columns: Excel column in, Word field out. AI document generation interprets the request and the data together, so it can interpret what each column means and shape the document's structure accordingly, produce conditional or analytical content, and assemble several documents from one instruction. The former is a mapping step; the latter is a generation task.
Can I generate personalized Word documents from an Excel file in C#?
Yes. Load a Word template or a blank document into Spire.Doc, attach the Excel workbook, and call ExecuteInstruction with a description of the personalized output. The agent reads each record and composes a document tuned to it, saved per record or as one combined file, all inside your own .NET application.
Can an AI agent use Excel data to generate Word documents?
Yes. Spire.Agent.Office pairs a language model with a deterministic Word and Excel layer, so the instruction is understood and the result is still a real Word file your team can open, format, and distribute. The agent interprets the spreadsheet's content rather than relying on a fixed column mapping, which is what makes heterogeneous inputs work.
Ready to Automate Your Word Generation?
If your workflow is "Excel data becomes personalized Word documents," the fastest path is to describe the output and let the agent handle the rest. Follow the Getting Started tutorial to run your first instruction-driven Word workflow in .NET.
Further Reading
- Generate Various Word Templates with Spire.Agent.Office -- the same generation pattern applied to different Word templates
- Automating Student Score Analysis and Ranking with Spire.Agent.Office -- an Excel-side workflow that feeds the documents this article generates
- Spire.Agent.Office product overview -- AI agent SDKs for every Office document format
AI Agent for Document Processing: What It Is and How It Works
Table of Contents

An AI agent for document processing is a software system that uses artificial intelligence models and tools to understand natural language instructions and perform tasks such as creating, editing, converting, analyzing, or extracting content from documents—without writing line-by-line code. An AI agent can work with Word, Excel, PowerPoint, and PDF files by interpreting user intent, selecting appropriate document-processing operations, and producing output that preserves the required file structure and formatting.
AI agents are one approach to automating document-related work. Other approaches include traditional programmatic APIs, raw language model endpoints used with custom code, and workflow engines that automate predefined steps. This article explains what AI-driven document processing is, how it differs from earlier methods, and when it makes sense to use it alongside other technologies.
1. What Is AI Document Processing?
Document processing—the activity of reading, creating, editing, converting, extracting information from, or analyzing digital documents—has always been one of the most common software tasks across industries. Email invoices arrive as PDFs. Sales reports sit inside Excel workbooks with inconsistent layouts. Employee handbooks live in Word templates that change every year. Legal agreements show up as scanned PDFs from external parties. For decades, organizations have written code to manage this variety.
Traditional document-processing approaches share a common pattern: someone defines what should happen to which documents using explicit rules. A template-fill script reads a CSV and populates a Word .docx by replacing predefined placeholders. A Python script iterates over Excel columns and calls layout functions to produce a styled report. A C# routine opens a PDF, searches for specific fields by position or regex pattern, and writes the results back into a database. These methods work well for stable, well-specified workflows—but they require programmatic instructions for every variation. When the template changes, when the input format shifts, or when new document types enter the pipeline, the code needs to be rewritten, tested, and redeployed.
AI-driven document processing extends those same operations by introducing a layer of language understanding. Instead of telling the software exactly which placeholder to replace or which cell range to read, you describe what result you want in natural language: "Summarize this contract and extract the payment terms," or "Compare last month's sales spreadsheet to this month's and save the analysis as a formatted report." The system uses an AI model to interpret that instruction, determines which document operations are needed, executes them against real file formats, and returns a properly structured output.
In practice, AI document processing does not replace traditional approaches—it augments them. Simple, predictable tasks may still be better handled by rule-based scripts because they are faster and fully deterministic. But when documents vary in structure, when inputs arrive in unpredictable formats, or when the question being asked of a document changes frequently, an AI-assisted approach saves engineering effort and adapts more naturally to shifting requirements.
2. What Is an AI Agent for Document Processing?
An AI agent for document processing is a system that combines language-model reasoning with document-oriented tools so a person can describe a task in conversational terms and have a real, well-formed document returned as output.
The defining characteristic of an agent—in this context—is that it bridges two capabilities that most individual components do not possess on their own:
- Understanding. The system interprets open-ended, high-level instructions about what to do with a document. "Review this agreement for risky clauses" or "Turn these quarterly figures into a presentation slide deck" are not structured queries; they require semantic comprehension.
- Action. After understanding the intent, the system selects and executes concrete document operations—reading a file, extracting text or tables, inserting content, changing layout, generating a new file—in formats like
.docx,.xlsx,.pptx, or.pdf.
Different vendors and research groups use slightly different terminology around these concepts. Some call these systems "AI assistants," others use "agentic workflows," "autonomous document pipelines," or "document intelligence platforms." The distinctions are subtle and often marketing-driven. What matters for evaluation is not the label but the capability: can the system both interpret unstructured instructions and manipulate document files through real APIs?
In practice, the term "document agent" covers several kinds of systems — including extraction-focused agents that ingest, classify, and route documents, and agents that directly interpret natural-language instructions and manipulate or generate documents. In this article the term refers specifically to agents that combine language-model reasoning with document-processing APIs. Below is a functional comparison that distinguishes an AI document agent from related technologies. These categories overlap significantly—many products combine several of them—but understanding where each approach excels helps clarify what an agent actually adds.
| Approach | Primary strength | How it handles instructions | Typical limitation |
|---|---|---|---|
| LLM endpoint only | Deep language understanding | Interprets natural language very effectively | Does not by itself provide deterministic, format-aware control over Office and PDF file structures; produces raw text or HTML unless combined with document-processing tools |
| Natural-language agent | Bridges understanding with tool execution | Takes high-level requests and chains appropriate tools together | Depends on quality of available tools and orchestration logic |
| Traditional SDK / API | Deterministic, precise file manipulation | Requires explicit programmatic commands; no language understanding | Rigid—every change in template or input format requires code updates |
| RPA (Robotic Process Automation) | Automates UI-level interactions across applications | Follows scripted workflows; some modern RPA includes vision and OCR | Struggles with ambiguous instructions that require semantic interpretation — RPA (Robotic Process Automation) is based on software robots that handle data across applications following predefined rules, whereas agents interpret open-ended natural-language requests |
| OCR (Optical Character Recognition) | Converts images / scans into machine-readable text | Operates on visual content; extracts characters and basic layout | Does not perform document generation, analysis, or multi-step workflows |
These capabilities often appear together in production systems. An enterprise document pipeline might use OCR to digitize scanned invoices, pass the extracted text through an LLM for semantic classification, route the result into an RPA workflow for data entry, and finally generate a branded report using a document API. An AI document agent sits at the center of such a pipeline as the component that understands the human request and coordinates whichever tools are needed to fulfill it.
When people search for "what is AI document processing" or "how AI document agents work," they are usually trying to understand whether buying or building such a system is different from combining off-the-shelf tools manually. The short answer: yes—when document variety, instruction variability, and formatting fidelity matter enough to justify a dedicated orchestration layer between language understanding and file manipulation.
3. How Does an AI Document Agent Work?
At a high level, an AI document agent follows five conceptual stages:
User provides natural language instruction
↓
AI model interprets intent and identifies needed operations
↓
Agent selects appropriate document-processing tools or APIs
↓
Document APIs execute file-level operations (read, modify, generate)
↓
Output document is generated using deterministic document-processing operations
Each stage introduces decisions that determine how accurate, reliable, and well-formatted the final output will be. Understanding these decisions clarifies why a pure LLM alone cannot reliably produce real Word or Excel files—and why a traditional SDK alone cannot understand a vague or open-ended request.
Architecture: From Intent to File
A typical implementation chains five layers, passing the document through each stage from intent to output:

Example: From a Natural-Language Request to a Finished Document
Consider a scenario that many finance teams encounter every month: a manager sends a folder of regional sales workbooks and asks for a consolidated summary report in Word format.
A user's natural-language request might read something like:
"Read all the Q3 sales files in this folder, compare each region to the previous quarter, summarize the key trends and outliers, and save the results as a formatted Word document."
Behind the scenes, the agent decomposes that single sentence into a sequence of operations:
- Discover and open every
.xlsxfile in the specified directory. - Read summary rows or key sheets from each workbook.
- Compute period-over-period changes.
- Identify the highest-performing and underperforming regions.
- Compose a narrative summary describing the trends.
- Create a new Word document, insert the summary, add tables showing regional comparisons, and apply formatting consistent with corporate templates.
The finished deliverable—the consolidated Word report with the narrative summary and regional comparison tables:

Without an agent, a developer would typically need to build and orchestrate each of those six steps—writing code for file discovery, reading data, computing changes, calling an LLM for prose generation, parsing its response, and mapping it into a structured document layout. With an agent, steps 4–6 can be expressed in a single instruction, while step 1–3 still leverage the same file-parsing capabilities your application already owns.
This kind of cross-format workflow—where reading data from one type of file and producing output in another requires both semantic reasoning and precise file manipulation—is exactly where AI agents provide the most value. Tools like Spire.Agent.Office package the orchestration layer together with deterministic document APIs so developers get a natural-language interface without losing control over formatting, layout, or output fidelity.
4. What Can AI Agents Do With Documents?
Depending on the capabilities of the underlying document-processing tools, AI agents can potentially cover a broad range of document operations that developers traditionally implement with explicit code—only expressed through intent rather than syntax. The table below shows representative operation categories that many implementations support when their underlying document-processing tools provide those capabilities.
| Capability | Word (.docx/.doc) | Excel (.xlsx/.xls) | PowerPoint (.pptx/.ppt) | PDF (.pdf) |
|---|---|---|---|---|
| Create from scratch or data | Yes — paragraphs, tables, headings, styles | Yes — sheets, cells, formulas, charts | Yes — slides, layouts, themes | Yes — sections, text blocks, annotations |
| Edit existing documents | Yes — insert, replace, reflow content | Yes — update cells, rearrange rows/columns | Yes — modify slide content, reorder | Yes — add/remove pages, annotate, redact |
| Convert between formats | Yes ↔ PDF, HTML, XPS, Markdown | Yes ↔ CSV, PDF, HTML | Yes ↔ PDF | Yes ↔ DOCX, HTML, image formats |
| Analyze / Summarize content | Yes — extract clauses, identify structure | Yes — compare datasets, compute statistics | Yes — review slide narratives | Yes — classify pages, extract key information |
| Extract data (structured) | Yes — pull text from paragraphs and tables | Yes — read cell values, ranges, named ranges | Limited — slide text and notes | Yes — parse forms, tables, embedded text |
Actual capabilities depend on the underlying document-processing libraries and the specific agent implementation.
Common use cases that fall under these capabilities include:
- Contract and agreement review: Read incoming PDFs or Word files, flag unusual clauses or missing provisions, and produce a Markdown or Word summary brief.
- Report consolidation: Aggregate disparate spreadsheets from multiple regions, detect anomalies, and generate a management-ready Word or PDF report.
- Presentation generation: Feed a briefing document or dataset into a presentation template and produce a finished slide deck with charts and talking points.
- Invoice and form processing: Open scanned or digital invoices, extract line items and totals, verify against purchase orders, and populate downstream systems.
- Policy and handbook maintenance: Update employee documents by replacing names, dates, and department-specific language across dozens of templates.
For teams that already build document workflows today, these capabilities do not replace their existing logic—they extend it. An agent handles the parts of a workflow that depend on human communication (understanding what to do), while the underlying document APIs handle the parts that depend on precision (producing the right file with the right layout). See the official tutorials on batch contract generation and generating presentations from documents for examples of how these operations fit into real applications.
5. Approaches to Document Automation
Not every organization reaches for an AI agent when automating document workflows. The technology choice depends on what kinds of documents you handle, how frequently they change, and how much engineering effort you have available. Below is a comparison of the primary approaches you will encounter in practice.
| Approach | Strengths | Limitations | Best suited for |
|---|---|---|---|
| Natural-language agent | Human-friendly interaction; minimal boilerplate; adapts to varied input formats | Requires integration with a document-processing layer; depends on model accuracy for complex instructions | Teams that receive documents with inconsistent structures and want rapid iteration without recompiling |
| LLM API + custom code | Highly customizable; pick best-of-breed models for each task; full control over orchestration | Significant engineering effort for file I/O, error handling, formatting, and validation | Organizations already running an LLM stack who want maximum flexibility and have engineering bandwidth |
| Traditional document SDK / API | Fully deterministic; precise control over layout, styling, and output consistency; no model dependency at runtime | Requires explicit programmatic instructions for every scenario; rigid when templates or input structures change frequently | Fixed-format documents with predictable structure that rarely change, such as standardized forms or compliance reports |
| RPA / workflow engine | Good for automating repeatable, rule-based processes across systems; leverages existing infrastructure | Less flexible for ambiguous or open-ended tasks; struggles when document formats vary widely | Back-office processes with high volume and low variance, such as invoice entry into ERP systems |
None of these approaches is universally superior. A mature document-automation strategy often combines more than one. For example, an organization might use traditional SDK code for generating fixed compliance reports and reserve an AI agent for ad-hoc analysis tasks that vary from week to week.
Where a solution like Spire.Agent.Office differentiates itself is in offering a single SDK that provides both the natural-language interface and the deterministic document-processing capabilities required to turn instructions into real files. Rather than wiring together separate LLM services, custom formatting libraries, and orchestration logic, developers add an AI processor to their existing document objects — a single AI(options) call on any Document, Workbook, Presentation, or PdfDocument instance — and then issue plain-language instructions that return formatted output while preserving layout, fonts, tables, and styles.
If you already use a traditional document library for deterministic operations, adding an agent layer typically means wrapping the same Document or Spreadsheet object with an AI processor and replacing field-by-field replacement logic with declarative instructions. The learning curve centers on writing effective prompts rather than learning a new file format.
6. AI Document Processing vs Intelligent Document Processing (IDP)
If you have researched document automation professionally, you will encounter several overlapping terms: AI document processing, intelligent document processing (or IDP), document intelligence, AI document automation, and AI document agent. Understanding their relationship helps narrow down what you are actually looking for—and avoids confusion caused by vendor terminology that varies across markets.
In common usage:
- AI document processing is often used as a broad umbrella term—it refers to any approach that applies artificial intelligence techniques to understand, create, edit, convert, or analyze documents. However, how broadly or narrowly this term is defined varies depending on who you ask.
- Intelligent Document Processing (IDP) originated in enterprise document management with an emphasis on the capture-and-extract phase: scanning or ingesting documents, classifying them by type (invoice, receipt, contract), applying OCR, extracting fields, validating against business rules, and routing to downstream systems. Over time, the boundaries of what counts as IDP have shifted as vendors incorporate generative AI into their products.
- Document intelligence is sometimes used interchangeably with IDP but often carries a stronger emphasis on extraction and understanding over generation. Vendors in the legal-tech and financial-services spaces favor this terminology.
- AI document automation highlights the execution side—using AI to trigger workflows that produce, send, or modify documents based on triggers or user requests.
- AI document agent focuses on the orchestrator aspect: a system that receives natural-language intent, plans the necessary operations, and delegates to whichever tools are required to complete the job.
These definitions are conventional rather than formal. You will find different vendors placing boundaries at different points, and many products span multiple categories simultaneously. The key takeaway is not which label your chosen tool carries but whether the tool can do what you actually need: understand a request, pick the right operations, execute them against real files, and return structured output.
For example, a system labeled "document intelligence platform" might excel at classification and extraction but lack strong generation capabilities. An "AI document agent" may support generation in addition to extraction, classification, and routing, depending on its tools and intended workflow. In practice, the best solutions combine extraction, reasoning, and generation under one roof—which is why frameworks like Spire.Agent.Office position themselves as end-to-end agents rather than point solutions for a single stage of the pipeline.
7. Why AI Agents Are Useful for Document Processing
The core reason AI agents matter for document work is simple: most meaningful document tasks involve three requirements simultaneously.
First, the system needs to understand what the user wants. "Prepare a quarterly summary from these reports" is not a structured query—it leaves unspecified which files to read, which metrics to extract, how to structure the output, and which tone to use. A language model excels at resolving that ambiguity.
Second, the system needs to execute actions against actual files. Generating coherent text in a chat window is different from producing a .docx with correct paragraph styles, page margins, table borders, and embedded charts. A language model by itself does not provide deterministic, format-aware control over Office file structures.
Third, the system needs to ensure the output preserves structure and formatting. Business documents carry constraints that go beyond readable text: clause numbering, section hierarchies, footer headers, merge fields, conditional formatting rules. These are structural properties that belong to the file format itself, not to plain text.
A traditional SDK is designed to address #2 and #3 deterministically, but it does not provide the language-level intent understanding described in #1. A raw LLM API can address #1 effectively, but does not by itself provide deterministic control over #2 and #3. Combining the two—putting a language model behind a deterministic document-processing layer—is what makes an agent useful for real-world document work.
Organizations that process high volumes of documents often face the same fundamental tension: documents require both semantic understanding (to figure out what to do) and deterministic file manipulation (to produce correctly formatted output). AI agents address this tension by combining both capabilities under one interface.
Industry analysts expect this combination to become the norm rather than the exception. Gartner predicts that by 2028, 33% of enterprise software applications will include agentic AI, up from less than 1% in 2024, and that 15% of day-to-day work decisions will be made autonomously—a shift with direct implications for document-heavy business workflows.
8. Frequently Asked Questions
What is the difference between an AI document agent and a regular LLM?
An LLM (Large Language Model) is a neural network trained to generate and understand text. It operates on sequences of tokens. By itself, it does not provide deterministic, format-aware control over Office or PDF file structures — though LLM-powered systems can access these formats through separate tools and APIs. An AI document agent sits on top of an LLM (or similar model) and connects it to document-processing tools that can open .docx, .xlsx, .pptx, and .pdf files, execute operations on them, and produce well-formed output. The LLM provides understanding; the agent provides the bridge to real files.
Do I need to send documents to the cloud to use an AI document agent?
Not necessarily. Many AI document agents can run entirely within your own infrastructure—the SDK or service runs on-premise or in a private cloud, and documents stay inside your environment. To analyze content, the relevant text layers are transmitted to the underlying model, which may reside on a hosted API or locally depending on configuration. If data privacy is a concern, look for solutions that support local model deployment or allow you to configure where model calls originate.
Which document formats do AI agents support?
AI document agents can support a wide range of formats, but the exact set varies considerably by implementation. Some agents focus primarily on PDF and image-based OCR workflows, while others handle full Microsoft Office file formats including Word (.docx, .doc), Excel (.xlsx, .xls), and PowerPoint (.pptx, .ppt). Many also support intermediate formats such as HTML, Markdown, XPS, CSV, and common image types for conversion purposes. Check the documentation for any product-specific limitations around encrypted files, legacy binary formats, or specialized templates.
Can I use my own AI model with a document agent SDK?
Some document-agent SDKs support flexible model integration, allowing developers to configure the provider or endpoint used by the agent. You can often choose between hosted services like OpenAI or Azure OpenAI, open-source models running in your environment, or proprietary endpoints provided by the SDK vendor. Supported providers vary by implementation, so consult the integration guide for the specific product you evaluate.
How does an AI document agent differ from RPA or OCR tools?
RPA (Robotic Process Automation) primarily automates predefined workflows and interactions, while AI agents can interpret higher-level instructions and dynamically select tools or actions based on context. Modern RPA systems sometimes incorporate OCR, NLP, or even LLMs themselves, but their core paradigm remains rule-based process automation.
OCR (Optical Character Recognition) primarily converts visual document content into machine-readable text, while an AI document agent can use OCR as one component in a broader workflow that includes interpretation and document operations. In practice, agents frequently invoke OCR internally when dealing with scanned documents but go far beyond text extraction to generate, format, and structure new files from what they find.
Is AI document processing suitable for enterprise workflows?
AI document processing is increasingly suitable for enterprise use, but readiness depends on several practical factors. On the positive side, modern document agents provide deterministic file manipulation that ensures output matches corporate templates and brand guidelines. They run inside existing application stacks without requiring users to learn new interfaces.
Key considerations before deployment include data privacy (how and where document text is transmitted), model reliability (handling edge cases where instructions are ambiguous), human-in-the-loop review processes for sensitive documents, and the ability to configure fallback behavior when a model call fails. Enterprises that pilot an agent for low-risk tasks first—internal memos, draft summaries, non-compliant templates—usually reach production deployments faster than those attempting enterprise-wide rollout on day one.
What is the difference between AI document processing and Intelligent Document Processing (IDP)?
Intelligent Document Processing (IDP) typically refers to enterprise-focused systems that specialize in the capture-and-extract phase of document workflows: ingesting documents, classifying them by type, applying OCR, extracting structured fields, validating against business rules, and routing to downstream systems. AI document processing is a broader umbrella term that encompasses IDP but also includes generation, transformation, cross-format workflows, and interactive agent-based automation.
A useful way to think about the distinction is that IDP traditionally emphasizes document ingestion, classification, extraction, validation, and downstream workflow orchestration, while AI document processing is often used more broadly to include analysis, generation, transformation, and agent-based reasoning. The two categories increasingly overlap as vendors incorporate generative capabilities into IDP platforms and agents adopt structured extraction pipelines.
Ready to Try AI Document Processing?
AI-driven document processing spans a wide range of use cases, from simple report generation to complex cross-format workflows that combine data analysis, summarization, and structured output. If you are evaluating options for integrating AI agents into a .NET application, start with the official Getting Started tutorial, then explore topic-specific guides on contract generation and presentation automation.
Further Reading
- Spire.Agent.Office product overview — AI agent SDK for Word, Excel, PowerPoint, and PDF document processing
- Batch Contract Generation tutorial — generating contracts from templates and data sources
- Generate PPT from Documents — turning Word, PDF, and other formats into presentations
- Automate Student Score Analysis in Excel — data analysis and ranking with AI agents
- Generate Various Word Templates — building templates the agent can fill
Automate Excel Report Generation with an AI Agent in C#

AI for Excel in C# means pairing a language model's judgment with a real Excel-processing library inside a .NET application, so the application can merge, normalize, analyze, and format spreadsheet data from natural-language instructions instead of column-by-column code. The hard part of Excel reporting has rarely been drawing the final chart — it is turning a pile of inconsistent source workbooks into data you can actually trust. With an AI agent you describe the reporting task ("merge these 20 store workbooks and flag stores whose revenue fell more than 30%") and get back a formatted workbook, not a chat answer. Spire.Agent.Office supplies both halves: the language understanding and a deterministic document layer that guarantees a real .xlsx (or PDF) comes out.
Quick Navigation
- From Heterogeneous Workbooks to a Common Data Model
- Turning Business Rules into Natural-Language Analysis
- From Analysis to a Management-Ready Report
- Building the Workflow in C#
- FAQ
1. The Real Bottleneck in Excel Report Automation
Take the recurring task behind most "monthly reporting" requests. An operations team runs 20 regional stores, and each store sends a sales workbook at month-end. In theory this is one report. In practice it is twenty different files that happen to share a filename pattern:
- The columns do not match. One store calls the figure
Revenue, anotherSales Amount, a thirdNet Sales. - The layout does not match. One store puts months across columns, another across rows, a third tacks a notes column in the middle.
- The data types do not match. Dates come in as text, numbers come in as thousands, and at least one store merges a title row into the header.
So before anyone can produce a chart for management, an analyst spends the week opening files, mapping columns, normalizing dates, hunting for typos, and only then checking for anomalies and assembling the report. None of that is the "report generation" part. It is all data preparation.
The point to internalize: the difficult part of Excel reporting is rarely creating the final chart. It is turning inconsistent source workbooks into data that can actually be trusted. A chart library will happily plot wrong data; what the team lacks is a reliable path from raw inbox files to a clean, comparable table. That path is exactly where an AI agent changes the economics.
2. What Changes When an AI Agent Enters the Workflow
Automation of this task is not new — it is just normally expensive. Compare the two workflows:
Traditional automation
Inspect files
→ map columns
→ normalize data
→ write rules
→ generate workbook
Every step before the last one is pre-defined: you write a column map for each known header, a date parser for each known format, and a threshold for each rule. The moment a store renames a column or a business rule changes, the map and the rules are wrong, and a human re-enters the loop.
Agent automation
Describe the reporting task
→ provide source workbooks
→ review result
The agent reads the meaning of each workbook rather than a fixed position, so the column map and the rule set no longer have to be enumerated up front. What it removes is precisely the expensive part: the work of pre-defining a schema and a rule set that will break on the next file.

The rest of this article walks that pipeline once, from raw workbooks to a printed PDF, using the 20-store scenario as the running example. Sections 3 through 5 explain what the agent does at each stage; section 6 gives the complete C# that drives it.
3. From Heterogeneous Workbooks to a Common Data Model
The Excel-specific version of the problem is that different workbooks "look the same" without actually being the same. Three stores can each send a table with four columns and still give you no way to merge them without human interpretation:
| Store A | Store B | Store C |
|---|---|---|
| Revenue | Sales Amount | Net Sales |
| Month | Reporting Period | Date |
| Units | Quantity Sold | Qty |
There is no column index that maps these onto each other, because the mapping is semantic, not positional. Revenue, Sales Amount, and Net Sales are three names for the same concept, and only understanding the header means you can align them.
The agent's consolidation step turns that semantic alignment into a single schema:
Store / Region / SKU / UnitsSold / Revenue / Month
It reads each source workbook, resolves the header names against that target model, aligns rows and columns, skips duplicate header and title rows, and writes one normalized table. The developer never writes a FindColumnByHeader("Revenue") routine — the instruction names the target schema, and the agent works out the mapping from each file.
This is the stage with the largest one-off payoff, because it is the stage that currently consumes the most analyst time and breaks most often when a new store joins.
4. Turning Business Rules into Natural-Language Analysis
Once the data is in one place, reporting needs judgment, and judgment is where hardcoded rules fail. The running example uses a typical finance rule:
Flag rows where revenue fell by more than 30% or grew by more than 50% versus the prior month.
Notice how much is packed into that sentence, and how awkward each part is as code:
- Why 30% and 50%? Those are business thresholds with context — a seasonal store, a new SKU, or a promotion changes what "unusual" means. A hardcoded
if (change < -0.30)treats every store identically and fires false alarms on seasonality. - How do you change it? In code, you recompile and redeploy. In the instruction, the analyst edits one sentence: "fell by more than 20%," or "only for the East region," or "flag only SKUs with more than 100 units sold."
- Add a dimension? Want the rule applied per store and per region and per month? You add a clause to the instruction, not a nested loop.
- Explain the result? The agent can append a
Causecolumn with a one-sentence likely explanation for each flagged row — something a threshold comparison alone can never produce.
The principle that falls out of this section is worth stating plainly:
Code defines how; instructions define what.
The developer stops encoding the rule and starts describing the outcome. The rule stays readable, editable by the business, and survives a new store or a changed threshold without a code change.
For a complete worked example of the same instruction-driven analysis applied to a ranking workflow, see the Student Score Analysis and Ranking tutorial.
5. From Analysis to a Management-Ready Report
Finding anomalies is only half of reporting. The result still has to become a workbook someone can actually use — the analyst's spreadsheet is not the deliverable; the management summary is.
The pipeline completes like this:
Raw Workbooks
↓
Consolidated Data
↓
Anomalies
↓
Management Summary
↓
PDF
The final instruction composes the deliverable: a Summary sheet up front with a KPI block (total revenue, top store, bottom store, count of flagged anomalies), a monthly trend table, a bar chart of revenue by region, and print-ready formatting. Pointing the same instruction at a .pdf path exports the identical report as a PDF for distribution, with no separate rendering step.
The point to carry forward: analysis and composition are two different jobs, and the agent does both. The analyst's job becomes reviewing the flagged shortlist and signing off, not rebuilding the deck each month.
6. Building the Workflow in C#
All the pieces above are driven by one C# pipeline. Configure the agent once, then run three instructions in sequence: consolidate, analyze, report. The full setup — token, packages, and project wiring — is documented step by step in the Getting Started tutorial; here we focus on the workflow itself.
using System.IO;
using Spire.Xls;
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
AIOptions options = new AIOptions {
SpireToken = spireToken,
WorkDir = @"C:\retail-ops\output",
TimeoutMs = 300000
};
string[] storeFiles = Directory.GetFiles(@"C:\retail-ops\inbox", "*.xlsx");
Directory.CreateDirectory(@"C:\retail-ops\output");
1. Consolidate. Pass the 20 inbox files as attachments and name the target schema. The normalization from section 3 happens here, driven by the instruction rather than any column map:
using (Workbook consolidated = new Workbook())
{
AIResult result = consolidated.AI(options).ExecuteInstruction(
consolidated,
"Read every regional sales workbook in the inbox and merge them into one worksheet. " +
"Each store names its columns differently (for example Sales vs Amount, Month vs Period); " +
"normalize them to a single schema: Store, Region, SKU, UnitsSold, Revenue, Month. Skip " +
"duplicate header rows and save the merged result as a workbook.",
@"C:\retail-ops\output\consolidated.xlsx",
storeFiles);
if (result == null || !result.Success)
throw new InvalidOperationException($"Consolidation failed: {result?.ErrorMessage}");
}
2. Analyze. Load the consolidated file and state the rule from section 4 in plain English. The agent adds an Anomalies sheet and leaves the source data untouched:
using (Workbook analysis = new Workbook())
{
analysis.LoadFromFile(@"C:\retail-ops\output\consolidated.xlsx");
AIResult result = analysis.AI(options).ExecuteInstruction(
analysis,
"Add an 'Anomalies' sheet. Compare each store and SKU's Revenue against the prior " +
"month, flag rows where revenue fell by more than 30% or grew by more than 50%, apply " +
"a red fill to declines and a green fill to jumps, and add a 'Cause' column with a " +
"one-sentence likely explanation. Leave the original data sheets unchanged.",
@"C:\retail-ops\output\analyzed.xlsx");
if (result == null || !result.Success)
throw new InvalidOperationException($"Analysis failed: {result?.ErrorMessage}");
}
The Anomalies sheet lands alongside the source data, with the flagged rows, fills, and Cause column applied by the instruction:

3. Report. Compose the management summary from section 5 and export it. The savePath alone chooses the format — .xlsx here, .pdf for distribution:
using (Workbook report = new Workbook())
{
report.LoadFromFile(@"C:\retail-ops\output\analyzed.xlsx");
AIResult result = report.AI(options).ExecuteInstruction(
report,
"Produce a management report. Add a 'Summary' sheet at the front with a KPI block " +
"(total revenue, top store, bottom store, count of flagged anomalies), a monthly trend " +
"table, and a bar chart of revenue by region. Format it for print and save the finished " +
"workbook.",
@"C:\retail-ops\output\monthly-report.xlsx");
if (result == null || !result.Success)
throw new InvalidOperationException($"Report generation failed: {result?.ErrorMessage}");
}
The Summary sheet lands at the front of the workbook, ready for print or PDF export:

Key API Calls
Workbook.AI(options)— attaches the AI document processor to an existing workbook objectExecuteInstruction(doc, instruction, savePath, attachments)— runs one stage and writes the resultAIResult.Success/AIResult.ErrorMessage— verifies each stage and surfaces failures
What You Would Write Without the Agent
For contrast, the traditional SDK route for the same three stages locates each column by header string, hardcodes every threshold, and sets every fill cell by cell — and re-tunes all of it when a store renames a column or the rule changes:
foreach (string file in storeFiles)
{
Workbook wb = new Workbook();
wb.LoadFromFile(file);
Worksheet sheet = wb.Worksheets[0];
// Fails the moment a store names the column "Sales" instead of "Revenue".
int revenueCol = FindColumnByHeader(sheet, "Revenue");
int storeCol = FindColumnByHeader(sheet, "Store");
for (int r = sheet.LastRow; r >= 2; r--)
{
double current = double.Parse(sheet.Range[r, revenueCol].Text);
double prior = double.Parse(sheet.Range[r, revenueCol + 1].Text);
double change = (current - prior) / prior;
// One hardcoded threshold; a seasonal store triggers false alarms.
if (change < -0.30) sheet.Range[r, revenueCol].Style.Color = Color.Red;
}
// ... then merge, then summary, then chart -- hundreds of lines per store and per month.
}

The agent does not remove the need for code — it removes the need for mapping code. The difference is where the logic lives: in a column finder and a threshold, or in a sentence the business can read and edit.
7. Where AI Stops and Application Logic Begins
A more honest way to think about the boundary than a list of "can and cannot": the agent does not eliminate deterministic application logic — it sits on top of it.
The application still owns everything that has nothing to do with understanding the spreadsheet:
- File discovery and access — finding the inbox files, checking permissions, and staging them
- Workflow scheduling — when the report runs, on what trigger, and in what order
- Data source control — which files are authorized inputs and where they come from
- Error handling and retries — what happens when a file is missing or a stage fails
- Final approval — a human reviews the flagged anomalies before sign-off
- External reconciliation — matching the report against a system of record
The agent owns the parts that are genuinely semantic:
- Understanding — reading what each column actually means
- Normalization — aligning heterogeneous schemas into one model
- Interpretation — applying a business rule to decide what is unusual
- Transformation — turning raw data into a summary, a chart, and formatting
- Composition — assembling the final workbook or PDF
This framing is more useful than a capability table because it tells you where to put your engineering effort. Keep the deterministic plumbing in code — where it is testable and auditable — and hand the semantic work to the agent. Each side does what it is good at.
8. Adding AI to an Existing .NET Excel Workflow
The last thing worth making explicit is how little you have to rebuild to get there. If your application already works with Excel through Spire.Xls, the document model you already hold is the integration point:
Workbook
↓
Workbook.AI(options)
↓
ExecuteInstruction(...)
You are not introducing a new document layer or a separate document-processing service. You are adding a natural-language execution layer onto the Workbook object you already have. The same object that opened, merged, and saved your files now accepts an instruction and carries out the workflow, with the deterministic Excel engine guaranteeing the output is a real, well-formed file — merged cells, number formats, and charts intact. The same ExecuteInstruction pattern extends to Word and PDF documents — see AI Contract Review in C#.
That is the value proposition for an Excel developer, stated in the terms you already think in: not "adopt an AI platform," but "teach the workbook you already use to take instructions." When a store renames a column or the finance team changes the flagging rule, the fix is an edit to a sentence, not a rebuild of the document pipeline.
9. FAQ
Do I need to send my Excel data to the cloud?
Not necessarily. Spire.Agent.Office runs from your own application, so the SDK and the document processing stay inside your environment; your files are not uploaded to a third-party service for storage or conversion. To analyze content, the AI needs the relevant data, and it is sent to the model for processing — an inherent step of any AI workflow. If you deploy your own model on your local network, the content stays entirely within your infrastructure. If you connect through a hosted model API such as OpenAI or Azure OpenAI, the relevant content is transmitted to that provider over the network per your configuration.
Which Excel formats does it support?
Input covers standard workbook files such as XLSX and XLS, and the agent reads the workbook directly in its native format. Output can be saved as XLSX, XLS, CSV, PDF, or HTML, so the finished report can go straight to an archive or a distribution list.
Can it replace my finance or operations review?
No. The agent automates the reading, normalization, analysis, and formatting — the hours an analyst spends each month — but the final sign-off stays with a human reviewer. Treat the flagged anomalies as a shortlist to verify, not a decision already made.
How is this different from pasting my data into ChatGPT?
A chat model can tell you what looks unusual but cannot place that answer into a styled workbook with a summary sheet, conditional formatting, and a chart, and it cannot export a PDF. An AI Excel agent pairs the language model's judgment with a deterministic Excel layer, so the output is a real, well-formed file your team can open and distribute.
Can I use my own AI model?
Yes. Spire.Agent.Office supports flexible AI model integration and is compatible with mainstream AI infrastructure, including hosted model APIs and privately deployed models. You can point the agent at your own endpoint. For questions about which providers are supported in your deployment, contact us.
Ready to Automate Your Excel Reporting?
Consolidation, anomaly analysis, and report generation are the fastest places to get value: point the agent at the inbox, describe the report, and get a formatted workbook or PDF out. Follow the Getting Started tutorial to run your first spreadsheet workflow in .NET.
Further Reading
- Automating Student Score Analysis and Ranking tutorial -- an Excel workflow the agent runs end to end
- AI Contract Review in C# -- the same instruction-driven pattern applied to Word and PDF documents
- Spire.Agent.Office product overview -- AI agent SDKs for every Office document format
AI Contract Review in C#: Automate Contract Processing in .NET

AI contract automation in C# means combining AI language understanding with document-processing capabilities inside your .NET application, so developers can review, extract, and generate contract documents by describing the task in natural language instead of writing field-mapping and layout code for every template. In practice, this is document automation in .NET where a natural-language instruction replaces the field-mapping code. Spire.Agent.Office is a document AI agent SDK that handles the language; a deterministic document layer guarantees real, well-formed Word and PDF files.
Quick Navigation
- Why Contract Review Is a Good Fit for AI
- What an AI Contract Agent Can and Cannot Do
- Common Contract Automation Scenarios
- Three Ways to Automate Contract Processing in .NET
- A Working Example: Contract Review and Generation in C#
- Why Use Spire.Agent.Office for AI Contract Automation
- FAQ
1. Why Contract Review Is a Good Fit for AI
Contract work in a developer's world is three repetitive jobs: reading (extracting parties, dates, payment terms, and obligations from agreements that arrive as PDFs and Word files), checking (spotting missing clauses or unusual language), and producing (turning a list of employees or vendors into signed-ready contracts).
For .NET developers, the challenge is not only understanding contract content; it is turning unstructured documents into structured, repeatable workflows your application can own.
Three properties make these tasks ideal for a language model rather than hand-written rules:
- The input is unstructured. Incoming contracts arrive in whatever format the other side sends. Rules that handle one layout break on the next; an LLM reads text directly.
- The output is document-shaped. The deliverable is a real
.docxor.pdfwith correct formatting, not a text blob. This is where a document layer earns its keep. - The volume changes constantly. Onboarding 50 employees or reviewing 200 vendor agreements in a month means a config-driven solution, not re-coding per template.
In practice, review and generation go together: teams want existing contracts summarized and red-flagged, and new contracts generated from a template plus structured data.
2. What an AI Contract Agent Can and Cannot Do
| Can do | Cannot do |
|---|---|
| Extract parties, effective dates, payment terms, obligations | Replace professional legal review for high-risk agreements |
| Summarize long agreements into a one-page brief | Guarantee compliance with local laws |
| Generate contracts in batches from a template + data source | Negotiate or accept terms on your behalf |
| Keep formatting, table styles, and fonts intact | Guarantee output is error-free without review |
| Run inside your own application (no cloud upload) | Interpret new or ambiguous regulations; route to counsel |
| Flag clauses that look unusual for a standard agreement | Reveal hidden risks in intentionally vague clauses |
The division of labor: the agent automates the reading, extraction, and drafting (the hours a paralegal would spend), while a human lawyer owns the final judgment. That boundary is what keeps the tool useful and the process defensible.
3. Common Contract Automation Scenarios
Contract automation spans more than hiring. The same pattern (an instruction, a template, and optional data) covers the scenarios teams search for most:
| Scenario | Example instruction |
|---|---|
| Vendor agreement review | "Review this vendor agreement and flag payment terms, liability caps, and termination conditions that differ from our standard terms." |
| Employment contract generation | "Generate one employment contract per row in 'employees.xlsx' using the template, preserving layout and styling." |
| NDA processing | "Summarize this NDA: confidentiality period, permitted disclosures, and remedies on breach." |
| Lease agreement analysis | "Extract rent, term, renewal options, and maintenance obligations from this lease, and list any unusual clauses." |
Each scenario is the same architecture: an instruction in, a real document out.
4. Three Ways to Automate Contract Processing in .NET
| Approach | Code volume | Format fidelity | Maintenance | Best for |
|---|---|---|---|---|
| Document AI agent (LLM + document layer) | One instruction + ~10 lines | High (real Word/PDF files) | Low (change behavior by editing instructions) | Teams automating contracts without building an LLM pipeline |
| Raw LLM API (OpenAI/Claude + your own code) | High (prompts, parsing, file I/O) | Low (LLMs don't natively read/write Office files) | High (you own RAG, routing, errors) | Teams that already run an LLM stack |
| Traditional SDK (Spire.Office or similar) | Dozens of lines per document type | High (deterministic) | High (every mapping is code) | Fixed, well-specified documents that rarely change |
The key point: an LLM cannot edit a contract template without a document-processing layer, and a traditional SDK cannot understand a natural-language request. A document AI agent combines both.
That is not to say the traditional route is wrong. For fixed, well-specified documents that rarely change, a deterministic SDK is often the right call, and Spire.Office still serves that need. The agent earns its place when templates, inputs, and requirements change often enough that re-coding becomes the bottleneck.
Why a Raw LLM API Is Not Enough for Contracts
Calling gpt-4 or claude directly to "generate a contract" fails in three ways that matter in production:
- It cannot reliably read or write Office files. LLMs see text, not
.docxand.pdfstructure. Reading a Word template, keeping a table intact, or producing a valid PDF usually requires a separate extraction and reconstruction pipeline you have to build yourself. - Formatting is not guaranteed. Contract templates carry clause numbering, tables, and fonts that matter to the recipient. A raw LLM returns text, and the formatting you lose is exactly what legal and HR departments care about.
- You reimplement the whole orchestration. Prompt design, field mapping, error handling, file I/O, and output validation become your code to own and maintain.
A document AI agent pairs the model's language understanding with deterministic document APIs: the model decides what to extract or fill, and the document layer guarantees the file is real and well-formed. That is the difference between a demo and a workflow a team can ship.
5. A Working Example: Contract Review and Generation in C#
Below is a task the legal and procurement teams repeat every week: reviewing newly arrived supplier agreements, then issuing contracts for the vendors that get approved. The implementation uses Spire.Agent.Office for .NET, an AI agent that processes Word, Excel, PowerPoint, and PDF documents through natural-language instructions. The example is designed around that workflow rather than copied from a tutorial; the official Getting Started and Batch Contract Generation tutorials document the API setup step by step, while this section focuses on the C# integration patterns.

1. Review every agreement that arrived this week. Configure the agent once, then read the inbox folder and have each agreement summarized as a Markdown brief you can paste into a review tracker:
using System.IO;
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;
using Spire.Pdf;
AIOptions agentOptions = new AIOptions();
agentOptions.WorkDir = @"C:\legal-ops\output";
agentOptions.SpireToken = spireToken;
string reviewPrompt =
"Review this supplier agreement and write a Markdown brief: a one-row table with " +
"the parties, effective date, payment terms, and termination clause, then a bullet " +
"list of any clauses that look unusual for a standard supplier agreement. " +
"Save the brief to the specified output path as Markdown.";
Directory.CreateDirectory(@"C:\legal-ops\output");
foreach (string file in Directory.GetFiles(@"C:\legal-ops\inbox", "*.pdf"))
{
string briefPath = Path.Combine(
@"C:\legal-ops\output", Path.GetFileNameWithoutExtension(file) + ".md");
using (PdfDocument agreement = new PdfDocument())
{
agreement.LoadFromFile(file);
AIResult result = agreement.AI(agentOptions).ExecuteInstruction(
agreement, reviewPrompt, briefPath, new string[] { });
if (result == null || !result.Success)
{
throw new InvalidOperationException(
$"Review failed for {Path.GetFileName(file)}: {result?.ErrorMessage}");
}
}
}
Key API Calls
PdfDocument.LoadFromFile()-- opens the supplier agreement PDFagreement.AI(agentOptions)-- attaches the AI document processorExecuteInstruction(doc, instruction, savePath, attachments)-- runs the review and writes the Markdown briefAIResult.Success/AIResult.ErrorMessage-- verifies the result and surfaces errors
Output

2. Issue contracts for the vendors you approved. One template plus the approval list. The template holds {{Placeholder}} markers for the vendor data; pass null as the output path so the agent writes one independent PDF per vendor into the working directory:
string[] attachments = { @"C:\legal-ops\data\approved-vendors.xlsx" };
using (Document contract = new Document())
{
contract.LoadFromFile(@"C:\legal-ops\templates\supplier-contract.docx");
AIResult result = contract.AI(agentOptions).ExecuteInstruction(
contract,
"Issue one purchase contract per approved vendor: read 'approved-vendors.xlsx' " +
"row by row, fill the {{Placeholder}} fields in this template with each vendor's " +
"data, preserve the template layout and styling, and save each contract as an " +
"independent PDF in the work directory.",
null, // null output path -> the agent writes each contract into WorkDir
attachments);
if (result == null || !result.Success)
{
throw new InvalidOperationException(
$"Contract issuing failed: {result?.ErrorMessage}");
}
}
Key API Calls
Document.LoadFromFile()-- loads the contract templatecontract.AI(agentOptions)-- attaches the AI document processorExecuteInstruction(doc, instruction, savePath, attachments)-- issues one independent contract per vendor rowAIResult.Success/AIResult.ErrorMessage-- verifies the result and surfaces errors
Output
Each contract is written to a session subfolder the agent manages under WorkDir (e.g. output\.office_use_tmp\Word\<session>\output_contracts), so point WorkDir at your archive folder and collect the issued contracts from there.

One template, one spreadsheet, and the same instruction drives every contract, each issued with its formatting intact. Output can be saved as PDF, DOCX, DOC, HTML, Markdown, or XPS to fit your archiving workflow. You can also build more complex templates than simple field filling -- the official Generate Various Word Templates tutorial covers placeholders, conditional sections, and other template patterns the agent can fill.
Why This Is Different: Traditional SDK vs. AI Agent
The value of the agent is clearest side by side. With the traditional SDK you locate each {{Placeholder}} and replace it by hand, one line per field, map every spreadsheet column to its placeholder, then loop the rows and export one file per row. That is dozens of lines you maintain every time the template or the data layout changes. The sketch below (simplified for illustration) shows the shape of that work:
// Traditional SDK (illustrative): every {{Placeholder}} is located and
// replaced by hand -- one line per field
Document doc = new Document();
doc.LoadFromFile(@"C:\legal-ops\templates\supplier-contract.docx");
doc.Replace("{{SupplierName}}", vendor.SupplierName, false, true);
doc.Replace("{{Amount}}", vendor.Amount.ToString(), false, true);
doc.Replace("{{PaymentTerms}}", vendor.PaymentTerms, false, true);
doc.Replace("{{EffectiveDate}}", vendor.EffectiveDate.ToString("yyyy-MM-dd"), false, true);
doc.SaveToFile(@"C:\legal-ops\output\PO-001.pdf"); // ...repeat for each vendor row
The AI agent replaces that orchestration with one instruction:
contract.AI(agentOptions).ExecuteInstruction(
contract,
"Issue one purchase contract per approved vendor: read 'approved-vendors.xlsx' " +
"row by row, fill the {{Placeholder}} fields in this template with each vendor's " +
"data, preserve the template layout and styling, and save each contract as an " +
"independent PDF in the work directory.",
null,
attachments);
Both produce the same contracts. Where the SDK grows a Replace call for every placeholder and a mapping for every column, the agent absorbs the same work into one instruction. When the template or the data layout changes, you edit the instruction, not the code.

6. Why Use Spire.Agent.Office for AI Contract Automation
The three-way comparison above is deliberately product-neutral; the same pattern works with any capable LLM. Where Spire.Agent.Office earns its place for .NET teams is in three specific areas:
- Native Office document processing. Word, Excel, PowerPoint, and PDF are first-class citizens, not formats you bolt on. The agent reads and writes real files across all four.
- Formatting is preserved. Enterprise contracts carry clause numbering, tables, and fonts that must survive processing. The agent's document layer keeps them intact. Include "preserve the original document layout and styling" in your instruction and the output stays true to the template.
- Native .NET integration. It is a C# SDK that drops into an existing .NET application. No separate document-processing service to build or maintain, no cross-service plumbing. The example above is the whole integration surface.
If you already run Spire.Office for document processing, the agent is the natural next layer: the same Document object gains an AI() processor that turns instructions into executed workflows.
7. FAQ
Can AI contract review work with text-based PDFs?
Yes. The review example above loads a supplier-agreement.pdf directly, and the agent reads and analyzes the document in its native format. Support covers standard and encrypted text-based PDFs. Image-only scans have no extractable text layer, so convert them to searchable text first (for example with OCR) before running the review.
Can contract data stay inside my environment?
Yes, with one important nuance. Spire.Agent.Office runs from your own application, so the SDK, templates, and document processing stay inside your environment. Contract files are not uploaded to a third-party document service for storage or conversion. To analyze contract content, the AI needs the relevant text, and it is sent to the model for processing; that is an inherent step of any AI workflow. If you deploy your own model on your local network, the content stays entirely within your infrastructure. If you connect through a hosted model API such as OpenAI or Azure OpenAI, the relevant content is transmitted to that provider over the network per your configuration.
Can I use my own AI model with Spire.Agent.Office?
Yes. Spire.Agent.Office supports flexible AI model integration and is compatible with mainstream AI infrastructure, including hosted model APIs and privately deployed models. You can point the agent at your own endpoint. See the integration tutorial for setup details; for questions about which providers are supported in your deployment, contact your account team at sales@e-iceblue.com.
Which model does Spire.Agent.Office use for contract review?
Spire.Agent.Office connects to a large language model behind a SpireToken key. You describe the review or generation task in natural language, and the agent orchestrates the underlying document-processing tools. The model handles understanding; the document layer guarantees formatting and file fidelity.
Can it generate contracts in batches?
Yes. One contract template plus a data source such as an Excel sheet, and one instruction produces one contract per data row. Both field filling and placeholder replacement are supported. For the agent to pick up every row, keep the first row of the data source as the header, put one vendor per row, and avoid blank rows; if the number of generated contracts does not match the data rows, check the data source first.
Will the AI change my contract's formatting?
Not if you say so. Include a phrase like "preserve the original document layout, styling, and fonts" in your instruction; the official tutorial documents this exact fix.
How is this different from using a raw LLM API?
A raw LLM cannot reliably read, edit, or write Word and PDF files on its own; it needs a document-processing layer. A document AI agent pairs the LLM's language understanding with deterministic document APIs, so the output is a real, well-formed file.
Ready to Automate Your Contract Workflow?
Contract review and batch generation are the fastest places to get value: one template, one data source, one natural-language instruction, and real Word or PDF files out. Follow the Getting Started tutorial to run your first document workflow in .NET.
Further Reading
- Spire.Agent.Office product overview -- AI agent SDKs for every Office document format
- Generate Various Word Templates tutorial -- building templates the agent can fill
Convert JSON Data to Excel in Java (JSON to XLSX Guide)

JSON is widely used for data exchange in REST APIs, web services, and enterprise applications. However, business users often prefer Excel for reporting, filtering, and data analysis. As a result, developers frequently need to convert JSON to Excel in Java when exporting API responses, generating reports, or sharing structured data with non-technical users.
While Java provides several JSON libraries, transforming data into a well-structured Excel file requires handling column headers, cell types, row iteration, and output formats — all of which become tedious without the right tool. Spire.XLS for Java simplifies this with a clean API that creates Excel workbooks without relying on Microsoft Office.
In this article, you'll learn how to convert JSON to Excel in Java using Spire.XLS for Java and Jackson. We'll cover JSON array conversion, nested JSON handling, JSON file processing, XLSX and XLS export, auto-fitting, formatting, and best practices for working with large datasets.
Quick Navigation
- Why Convert JSON to Excel in Java
- Install Spire.XLS for Java
- Prepare JSON Data
- Convert JSON to Excel in Java — Step by Step
- Complete Java Code to Convert JSON to Excel
- Export JSON to XLSX in Java
- Convert Nested JSON to Excel in Java
- Convert a JSON File to Excel
- Auto-Fit Rows and Columns in Excel
- Apply Formatting to the Exported Excel File
- Common Challenges When Converting JSON to Excel
- Why Use Spire.XLS for Java
- Conclusion
- FAQ
1. Why Convert JSON to Excel in Java
JSON is widely used for data exchange in REST APIs, web services, and enterprise applications because it is lightweight and easy for machines to process. However, business users often need Excel files for reporting, filtering, visualization, and further analysis.
Converting JSON to Excel in Java helps bridge the gap between backend systems and business workflows. Common use cases include:
Export API Data
Many REST APIs return JSON responses. Converting these responses into Excel allows users to review, filter, and analyze data without manually processing raw JSON.
Generate Reports
Java applications can transform JSON data from APIs, databases, or other sources into structured Excel reports with headers, formatting, and organized tables.
Share Structured Data
Excel files are easier to distribute and analyze using tools such as charts, formulas, and pivot tables. Exporting JSON data to Excel gives non-technical users direct access to these features.
2. Install Spire.XLS for Java
Before converting JSON to Excel in Java, set up the following dependencies in your project.
Maven Dependency
Spire.XLS for Java is available through the e-iceblue Maven repository. Add the repository and dependency to your pom.xml:
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls</artifactId>
<version>16.6.5</version>
</dependency>
You can also download Spire.XLS for Java and add the JAR to your project manually.
Add a JSON Library
Java does not include built-in JSON support. This guide uses Jackson, the most widely adopted JSON processing library in the Java ecosystem:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
Import Required Classes
Include the following imports in your Java source file:
import com.spire.xls.*;
import com.spire.xls.core.spreadsheet.collections.AutoFitType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
3. Prepare JSON Data
To illustrate the conversion process, we will use a simple JSON array where each object represents a row and each property represents a column. This is the most common JSON structure encountered in REST API responses and data export workflows.
Example: Simple JSON Array
[
{
"ID": 1,
"Name": "Alice",
"Department": "Sales",
"Salary": 75000,
"HireDate": "2022-03-15"
},
{
"ID": 2,
"Name": "Bob",
"Department": "Marketing",
"Salary": 68000,
"HireDate": "2021-07-01"
},
{
"ID": 3,
"Name": "Carol",
"Department": "Engineering",
"Salary": 92000,
"HireDate": "2023-01-10"
}
]
The mapping between JSON and Excel is straightforward:
- Each JSON object becomes a row in the spreadsheet
- Each property key becomes a column header
- Each property value becomes a cell value in the corresponding row and column
Understanding this mapping is essential for following the code examples in the next sections.
4. Convert JSON to Excel in Java — Step by Step
The conversion process involves five steps: creating a workbook, accessing a worksheet, parsing JSON data, writing column headers, and populating cell values. This section walks through each step individually before presenting the complete code.
Step 1: Create a Workbook
The Workbook class represents an Excel file. Instantiate it to create a new, empty workbook:
Workbook workbook = new Workbook();
Step 2: Create a Worksheet
A workbook contains one or more worksheets. Access the first worksheet (created by default) and optionally rename it:
Worksheet sheet = workbook.getWorksheets().get(0);
sheet.setName("EmployeeData");
Step 3: Read JSON Data
Use Jackson's ObjectMapper to parse the JSON string into a JsonNode tree. If the root element is a JSON array, cast it to ArrayNode for iteration:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);
if (!rootNode.isArray()) {
throw new IllegalArgumentException("Expected a JSON array at the root level");
}
ArrayNode jsonArray = (ArrayNode) rootNode;
Step 4: Write JSON Keys as Column Headers
Extract the field names from the first JSON object and write them to the first row of the worksheet. Spire.XLS uses 1-based row and column indices:
JsonNode firstObject = jsonArray.get(0);
int col = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = firstObject.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
sheet.get(1, col).setValue(entry.getKey());
col++;
}
Step 5: Write JSON Values to Excel Cells
Iterate through each JSON object in the array and write its values to the corresponding row. Start from row 2 since row 1 contains the headers:
for (int i = 0; i < jsonArray.size(); i++) {
JsonNode record = jsonArray.get(i);
int dataRow = i + 2;
int dataCol = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = record.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
JsonNode value = entry.getValue();
if (value.isNumber()) {
sheet.get(dataRow, dataCol).setNumberValue(value.doubleValue());
} else if (value.isBoolean()) {
sheet.get(dataRow, dataCol).setBooleanValue(value.booleanValue());
} else {
sheet.get(dataRow, dataCol).setValue(value.asText());
}
dataCol++;
}
}
This approach preserves data types — numbers and booleans are written as typed cell values rather than strings, which ensures that numeric sorting, filtering, and formula calculations work correctly in the generated Excel file.
5. Complete Java Code to Convert JSON to Excel
Here is the full, runnable program that reads a JSON string and converts it to an Excel file. This example demonstrates the complete Java code to convert JSON to Excel from start to finish:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.util.Iterator;
import java.util.Map;
public class JsonToExcelConverter {
public static void main(String[] args) {
// Sample JSON data — an array of employee records
String jsonString = "["
+ "{\"ID\":1,\"Name\":\"Alice\",\"Department\":\"Sales\",\"Salary\":75000,\"HireDate\":\"2022-03-15\"},"
+ "{\"ID\":2,\"Name\":\"Bob\",\"Department\":\"Marketing\",\"Salary\":68000,\"HireDate\":\"2021-07-01\"},"
+ "{\"ID\":3,\"Name\":\"Carol\",\"Department\":\"Engineering\",\"Salary\":92000,\"HireDate\":\"2023-01-10\"}"
+ "]";
try {
// Parse the JSON string into a JsonNode tree
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonString);
if (!rootNode.isArray()) {
throw new IllegalArgumentException("Expected a JSON array at the root level");
}
ArrayNode jsonArray = (ArrayNode) rootNode;
// Create a new workbook and access the first worksheet
Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);
sheet.setName("EmployeeData");
// Write column headers from the first JSON object's keys
JsonNode firstObject = jsonArray.get(0);
int col = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = firstObject.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
sheet.get(1, col).setValue(entry.getKey());
col++;
}
// Write data rows from JSON values
for (int i = 0; i < jsonArray.size(); i++) {
JsonNode record = jsonArray.get(i);
int dataRow = i + 2;
int dataCol = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = record.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
JsonNode value = entry.getValue();
// Preserve data types: numbers and booleans as typed cells
if (value.isNumber()) {
sheet.get(dataRow, dataCol).setNumberValue(value.doubleValue());
} else if (value.isBoolean()) {
sheet.get(dataRow, dataCol).setBooleanValue(value.booleanValue());
} else {
sheet.get(dataRow, dataCol).setValue(value.asText());
}
dataCol++;
}
}
// Auto-fit columns for readability
sheet.getAllocatedRange().autoFitColumns();
// Save the workbook as an XLSX file
workbook.saveToFile("EmployeeData.xlsx", ExcelVersion.Version2016);
System.out.println("JSON converted to Excel successfully.");
// Release resources
workbook.dispose();
} catch (Exception e) {
System.err.println("Error during JSON to Excel conversion: " + e.getMessage());
e.printStackTrace();
}
}
}
After running the program, the JSON data is converted into an Excel worksheet. The generated EmployeeData.xlsx file contains the employee records with preserved data types and automatically adjusted column widths:

Key Spire.XLS Classes and Methods
- Workbook — Represents an Excel file. Handles creation, worksheet management, and file saving.
- Worksheet — Represents a single sheet within a workbook. Provides access to cells, rows, and columns.
get(int row, int column)— Returns aCellRangeobject for the specified cell. Row and column indices are 1-based.setValue(String)— Sets a cell's value as a string. Used for text and headers.setNumberValue(double)— Sets a cell's value as a number, preserving numeric type for calculations.setBooleanValue(boolean)— Sets a cell's value as a boolean (TRUE/FALSE).saveToFile(String, ExcelVersion)— Saves the workbook to a file in the specified Excel format.dispose()— Releases unmanaged resources held by the workbook.
If you also need to convert Excel files back to JSON format, see our guide on how to convert Excel to JSON in Java using Spire.XLS for Java.
6. Export JSON to XLSX in Java
Spire.XLS for Java supports both the modern XLSX format (Excel 2007 and later) and the legacy XLS format (Excel 97–2003). You can control the output format by passing the appropriate ExcelVersion enum to saveToFile().
Save as XLSX
// Export to modern Excel format (.xlsx)
workbook.saveToFile("EmployeeData.xlsx", ExcelVersion.Version2016);
Save as XLS
// Export to legacy Excel format (.xls)
workbook.saveToFile("EmployeeData.xls", ExcelVersion.Version97to2003);
| Format | Description | Use Case |
|---|---|---|
| XLSX | Modern Excel format (Excel 2007+) | Default choice; smaller file, full features |
| XLS | Legacy Excel format (Excel 97–2003) | Compatibility with older systems |
The same workbook object can be saved to either format — no code changes are needed beyond the file extension and version parameter. This is particularly useful when your application needs to support both modern and legacy environments.
You can also learn how to convert between XLS and XLSX formats in Java for scenarios where format migration or legacy upgrade is required.
7. Convert Nested JSON to Excel in Java
Real-world JSON data often contains nested objects and arrays. To write nested JSON to Excel, you need to flatten the hierarchical structure into a tabular format where each nested field becomes its own column.
Consider the following JSON containing employee records with nested contact information:
[
{
"ID": 1,
"Name": "Alice",
"Department": "Sales",
"Contact": {
"Email": "alice@company.com",
"Phone": "555-0101"
}
},
{
"ID": 2,
"Name": "Bob",
"Department": "Marketing",
"Contact": {
"Email": "bob@company.com",
"Phone": "555-0102"
}
}
]
The goal is to flatten the Contact object so that Email and Phone become individual columns:
| ID | Name | Department | Contact.Email | Contact.Phone |
|---|---|---|---|---|
| 1 | Alice | Sales | alice@company.com | 555-0101 |
| 2 | Bob | Marketing | bob@company.com | 555-0102 |
The following code uses a recursive flattening approach to handle arbitrary nesting depth:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class NestedJsonToExcel {
public static void main(String[] args) {
String jsonString = "["
+ "{\"ID\":1,\"Name\":\"Alice\",\"Department\":\"Sales\","
+ "\"Contact\":{\"Email\":\"alice@company.com\",\"Phone\":\"555-0101\"}},"
+ "{\"ID\":2,\"Name\":\"Bob\",\"Department\":\"Marketing\","
+ "\"Contact\":{\"Email\":\"bob@company.com\",\"Phone\":\"555-0102\"}}"
+ "]";
try {
ObjectMapper mapper = new ObjectMapper();
ArrayNode jsonArray = (ArrayNode) mapper.readTree(jsonString);
Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);
sheet.setName("Employees");
// Flatten the first object to extract all column headers (including nested keys)
LinkedHashMap<String, String> firstFlat = flattenJson(jsonArray.get(0), "");
int col = 1;
for (String key : firstFlat.keySet()) {
sheet.get(1, col).setValue(key);
col++;
}
// Write data rows
for (int i = 0; i < jsonArray.size(); i++) {
LinkedHashMap<String, String> flat = flattenJson(jsonArray.get(i), "");
int dataRow = i + 2;
int dataCol = 1;
for (String key : firstFlat.keySet()) {
String value = flat.getOrDefault(key, "");
sheet.get(dataRow, dataCol).setValue(value);
dataCol++;
}
}
sheet.getAllocatedRange().autoFitColumns();
workbook.saveToFile("NestedEmployees.xlsx", ExcelVersion.Version2016);
System.out.println("Nested JSON converted to Excel successfully.");
workbook.dispose();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
/**
* Recursively flattens a JSON object into key-value pairs.
* Nested keys are joined with a dot (e.g., "Contact.Email").
*/
private static LinkedHashMap<String, String> flattenJson(JsonNode node, String prefix) {
LinkedHashMap<String, String> flat = new LinkedHashMap<>();
if (node.isObject()) {
for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
String newPrefix = prefix.isEmpty() ? entry.getKey() : prefix + "." + entry.getKey();
flat.putAll(flattenJson(entry.getValue(), newPrefix));
}
} else {
flat.put(prefix, node.asText());
}
return flat;
}
}
The flattenJson method recursively traverses each JSON object. When it encounters a nested object, it prepends the parent key with a dot separator (e.g., Contact.Email). When it reaches a leaf value, it stores the full dotted key and its value in the map. This ensures that all fields — at any nesting depth — are represented as columns in the resulting Excel sheet.

8. Convert a JSON File to Excel
In production applications, JSON data typically comes from a file on disk rather than an inline string. The conversion steps remain the same — only the JSON source changes. Jackson's ObjectMapper can read directly from a File object:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.util.Iterator;
import java.util.Map;
public class JsonFileToExcel {
public static void main(String[] args) {
try {
// Step 1: Read and parse the JSON file
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(new File("employees.json"));
if (!rootNode.isArray()) {
throw new IllegalArgumentException("Expected a JSON array at the root level");
}
ArrayNode jsonArray = (ArrayNode) rootNode;
// Step 2: Create a workbook
Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);
sheet.setName("Employees");
// Step 3: Write headers from the first object
JsonNode firstObject = jsonArray.get(0);
int col = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = firstObject.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
sheet.get(1, col).setValue(entry.getKey());
col++;
}
// Step 4: Write data rows
for (int i = 0; i < jsonArray.size(); i++) {
JsonNode record = jsonArray.get(i);
int dataRow = i + 2;
int dataCol = 1;
for (Iterator<Map.Entry<String, JsonNode>> it = record.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> entry = it.next();
JsonNode value = entry.getValue();
if (value.isNumber()) {
sheet.get(dataRow, dataCol).setNumberValue(value.doubleValue());
} else if (value.isBoolean()) {
sheet.get(dataRow, dataCol).setBooleanValue(value.booleanValue());
} else {
sheet.get(dataRow, dataCol).setValue(value.asText());
}
dataCol++;
}
}
// Step 5: Export to Excel
sheet.getAllocatedRange().autoFitColumns();
workbook.saveToFile("EmployeesFromJson.xlsx", ExcelVersion.Version2016);
System.out.println("JSON file converted to Excel successfully.");
workbook.dispose();
} catch (Exception e) {
System.err.println("Error reading JSON file: " + e.getMessage());
e.printStackTrace();
}
}
}
This approach handles large JSON files efficiently because Jackson processes the file as a streaming tree model. For very large JSON files (hundreds of megabytes), consider using Jackson's JsonParser in streaming mode to read records incrementally rather than loading the entire tree into memory at once.
9. Auto-Fit Rows and Columns in Excel
When JSON data is written to Excel cells, the default column width may not be wide enough to display all content. Text values such as email addresses, URLs, or long descriptions get truncated visually. Spire.XLS provides auto-fit methods that adjust column widths and row heights to match their content:
// Auto-fit all columns and rows in the used range
sheet.getAllocatedRange().autoFitColumns();
sheet.getAllocatedRange().autoFitRows();
Add these lines after writing all data but before saving the workbook. The getAllocatedRange() method returns the range of cells that contain data, so only populated cells are affected.
For more granular control, you can auto-fit individual columns:
// Auto-fit a specific column (e.g., column 3)
sheet.getAllocatedRange().getColumns()[2].autoFitColumns();
Auto-fitting produces a more professional, readable spreadsheet — especially when the JSON data contains variable-length text fields. The screenshot below shows the difference between a raw export and one with auto-fit applied.
10. Apply Formatting to the Exported Excel File
Raw data exports often need formatting to meet business reporting standards. Spire.XLS for Java provides a rich set of cell formatting APIs that let you style the header row, format numbers, and apply date formats — all programmatically.
Format the Header Row
Apply bold text and a background color to the first row to distinguish headers from data:
import com.spire.xls.core.spreadsheet.styles.CellStyle;
import java.awt.Color;
// Apply formatting to the header row
CellRange headerRange = sheet.getAllocatedRange().getRows()[0];
headerRange.getStyle().setFont(new ExcelFont(true));
headerRange.getStyle().setColor(Color.decode("#4472C4"));
headerRange.getStyle().getFont().setColor(Color.WHITE);
headerRange.setStyle(headerRange.getStyle());
Format Numbers
Apply currency or percentage formatting to numeric columns:
// Format the Salary column (column 4) as currency
CellRange salaryColumn = sheet.getAllocatedRange().getColumns()[3];
salaryColumn.setNumberFormat("$#,##0.00");
Format Dates
If your JSON contains date strings, you can format the corresponding column to display them in a consistent format:
// Format the HireDate column (column 5) as a date
CellRange dateColumn = sheet.getAllocatedRange().getColumns()[4];
dateColumn.setNumberFormat("yyyy-mm-dd");
The formatting techniques above can be combined to create professional Excel reports. For a complete Java example covering advanced Excel formatting features, refer to How to Create and Format Excel Files in Java Using Spire.XLS.
11. Common Challenges When Converting JSON to Excel
Real-world JSON data is rarely as clean as tutorial examples. Here are the most common challenges developers face when converting JSON to Excel, along with practical solutions.
Missing Fields Across Objects
Different JSON objects in the same array may have inconsistent fields. One record might include a Phone field while another omits it entirely. If your code assumes all objects share the same keys, missing fields cause index misalignment in the Excel output.
Solution: Collect all unique keys across all objects first, then write each object's values using the unified key list:
// Collect all unique keys from all JSON objects
LinkedHashSet<String> allKeys = new LinkedHashSet<>();
for (JsonNode record : jsonArray) {
record.fieldNames().forEachRemaining(allKeys::add);
}
// Write headers from the complete key set
int col = 1;
for (String key : allKeys) {
sheet.get(1, col).setValue(key);
col++;
}
// Write values, using empty string for missing fields
for (int i = 0; i < jsonArray.size(); i++) {
JsonNode record = jsonArray.get(i);
int dataRow = i + 2;
int dataCol = 1;
for (String key : allKeys) {
JsonNode value = record.get(key);
String cellValue = (value != null && !value.isNull()) ? value.asText() : "";
sheet.get(dataRow, dataCol).setValue(cellValue);
dataCol++;
}
}
Nested Objects
JSON objects can contain arbitrarily deep nesting. Writing nested objects directly to cells produces unreadable output like [object Object] or serialized JSON strings.
Solution: Use the recursive flattening approach demonstrated in Section 7. The flattenJson method traverses the entire object tree and produces flat key-value pairs where nested keys are joined with dot notation.
Large JSON Files
Parsing very large JSON files (hundreds of megabytes or more) into a single in-memory tree can cause OutOfMemoryError in Java. Additionally, writing tens of thousands of rows one cell at a time can be slow.
Solution: Use Jackson's streaming API (JsonParser) to read JSON records one at a time, and write each record to Excel immediately before moving to the next. This keeps memory usage constant regardless of file size:
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
JsonFactory factory = new JsonFactory();
try (JsonParser parser = factory.createParser(new File("large_data.json"))) {
int dataRow = 2;
while (parser.nextToken() != JsonToken.END_ARRAY) {
// Parse one object at a time
JsonNode record = mapper.readTree(parser);
// Write to Excel...
dataRow++;
}
}
Data Type Conversion
JSON supports strings, numbers, booleans, null values, arrays, and objects. Excel cells support text, numbers, booleans, dates, and errors. Mismatched types — for example, storing a numeric value as a string — prevent Excel sorting and formulas from working correctly.
Solution: Check each JSON value's type before writing it to a cell. Use setNumberValue() for numbers, setBooleanValue() for booleans, and setValue() for text. Handle null values by writing an empty string or a placeholder. For date strings, parse them into Date objects and use setDateTimeValue() to write them as Excel date cells:
if (value == null || value.isNull()) {
sheet.get(dataRow, dataCol).setValue("");
} else if (value.isNumber()) {
sheet.get(dataRow, dataCol).setNumberValue(value.doubleValue());
} else if (value.isBoolean()) {
sheet.get(dataRow, dataCol).setBooleanValue(value.booleanValue());
} else {
sheet.get(dataRow, dataCol).setValue(value.asText());
}
12. Why Use Spire.XLS for Java for JSON-to-Excel Conversion
Several characteristics make Spire.XLS for Java well-suited for JSON-to-Excel conversion in enterprise Java applications.
No Microsoft Excel Required
Spire.XLS for Java is a standalone library that does not depend on Microsoft Office or any other external software. It runs on any system with a Java Runtime Environment, including Linux servers, Docker containers, and cloud platforms where Office is not available.
Supports XLS and XLSX
The library handles both the legacy XLS format (Excel 97–2003) and the modern XLSX format (Excel 2007+). You can export to either format by changing a single parameter, making it easy to support diverse downstream environments.
Rich Formatting Features
Beyond basic cell value writing, Spire.XLS provides comprehensive formatting capabilities — cell styles, number formats, fonts, colors, borders, conditional formatting, charts, and pivot tables. This allows you to generate professional-grade Excel files directly from JSON data without any post-processing in Excel.
Easy API
The API follows an intuitive object model: Workbook contains Worksheets, each Worksheet contains CellRanges, and each CellRange supports value setting, styling, and formatting. Developers familiar with the Excel object model can become productive quickly.
Suitable for Enterprise Applications
Spire.XLS for Java is designed for server-side and enterprise use cases. It handles large files efficiently, supports multi-threaded access patterns, and integrates cleanly with Spring Boot, Jakarta EE, and other Java frameworks commonly used in enterprise environments.
You can apply for a 30-day free license to evaluate all features in your projects.
13. Conclusion
In this article, we explored how to convert JSON to Excel in Java using Spire.XLS for Java and Jackson. By parsing JSON data, writing values into Excel worksheets, and exporting the workbook as XLSX or XLS files, developers can efficiently transform structured JSON data into readable spreadsheets.
Spire.XLS for Java provides a simple and flexible way to generate Excel files from JSON data without requiring Microsoft Office or external dependencies. It also supports advanced features such as formatting, auto-fitting, and handling complex data structures for professional Excel reports.
14. FAQ
How do I convert JSON to Excel in Java?
Parse the JSON data using Jackson's ObjectMapper, create a Workbook and Worksheet using Spire.XLS for Java, write the JSON keys as column headers in the first row, then iterate through the JSON array to populate each data row. Save the workbook using saveToFile() with the desired ExcelVersion. The complete code example is shown in Section 5.
Can I convert JSON to XLSX in Java without Microsoft Excel installed?
Yes. Spire.XLS for Java is a standalone library that does not require Microsoft Office or any other software. It can create, read, and write XLSX files entirely in Java, making it suitable for server-side applications running on Linux, Docker, or cloud platforms.
How do I handle nested JSON objects when converting to Excel?
Use a recursive flattening function that traverses the JSON object tree and produces flat key-value pairs. Nested keys are joined with a dot separator (e.g., Contact.Email). The flattened keys become column headers in the Excel sheet. See Section 7 for the complete implementation.
What is the difference between setValue() and setNumberValue() in Spire.XLS?
setValue(String) writes a string value to a cell, while setNumberValue(double) writes a numeric value that Excel treats as a number. Using setNumberValue() for numeric JSON fields ensures that sorting, filtering, and formula calculations work correctly. Similarly, setBooleanValue(boolean) writes typed boolean values.
How do I convert a large JSON file to Excel without running out of memory?
For large JSON files, use Jackson's streaming API (JsonParser) to read and process one JSON record at a time instead of loading the entire file into memory. Write each record to the Excel worksheet immediately after parsing it. This keeps memory usage constant regardless of the file size.
Is Spire.XLS for Java free?
Spire.XLS for Java is a commercial library. A free version, Free Spire.XLS for Java, is available with limitations on worksheet count and features. You can also apply for a 30-day free license to evaluate the full feature set before purchasing.
Convert Excel to JSON in Java (Multi-Sheet & Nested JSON)

Converting Excel to JSON in Java is a common requirement in backend development, especially when building APIs, ETL pipelines, or data integration workflows. In this guide, you will learn how to convert Excel to JSON in Java using Spire.XLS, a powerful library that supports both XLS and XLSX formats with minimal code.
Excel files are widely used for data storage and reporting, while JSON has become the standard format for data exchange in modern applications. However, converting Excel to JSON in Java is not trivial if done manually — developers need to handle file parsing, data type conversion, empty cells, and multi-sheet structures, which can quickly become complex and error-prone.
Using Spire.XLS for Java together with Jackson, developers can easily transform Excel spreadsheets into structured JSON data with clean and maintainable code. This article provides a complete step-by-step tutorial on Java Excel to JSON conversion, including single-sheet conversion, multi-sheet processing, and nested JSON structures.
Quick Navigation
- Why Convert Excel to JSON in Java
- Prerequisites
- Convert Excel to JSON in Java — Step by Step
- Convert XLS and XLSX Files to JSON
- Handling Multi-Sheet Workbooks and Nested JSON
- Handling Empty Cells and Data Types
- Common Pitfalls
- Conclusion
- FAQ
1. Why Convert Excel to JSON in Java
Excel and JSON are widely used in modern software systems but serve very different roles. Excel is designed for structured data entry, analysis, and reporting with support for formulas, formatting, and multi-sheet workbooks. JSON (JavaScript Object Notation), in contrast, is a lightweight data format used for machine-to-machine communication, REST APIs, configuration files, and NoSQL databases.
Because of this difference, Java developers often need to convert Excel to JSON when integrating spreadsheet-based data into backend systems.
Common use cases include:
- REST API integration — Converting Excel data uploaded by users into JSON for API responses
- ETL workflows — Extracting spreadsheet data and transforming it into JSON for databases or data lakes
- Configuration migration — Moving legacy Excel-based configs into JSON-based microservice systems
- Automated reporting — Turning Excel templates into structured JSON for downstream processing
In Java applications, converting Excel to JSON is more than just reading rows and mapping columns. Real-world files often include inconsistent data types, empty cells, date formatting issues, and multi-sheet structures, which make manual parsing complex and error-prone.
Spire.XLS for Java simplifies this process by providing a unified API for both XLS and XLSX formats. It allows developers to directly access cell values, data types, and formatting information, enabling clean and reliable Excel to JSON conversion logic without dealing with low-level file parsing.
2. Prerequisites
Before converting Excel to JSON in Java, set up the following dependencies in your project.
Install Spire.XLS for Java via Maven (Recommended)
Spire.XLS for Java is available through the e-iceblue Maven repository. Add the repository and dependency to your pom.xml:
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls</artifactId>
<version>16.6.5</version>
</dependency>
You can also download Spire.XLS for Java and add it to your project manually.
Add a JSON Library
Java does not include built-in JSON support. This guide uses Jackson, the most widely adopted JSON processing library in the Java ecosystem:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
Import Required Classes
Include the following imports in your Java source file:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.io.IOException;
If you prefer manual installation, download the Spire.XLS for Java JAR from the e-iceblue website and add it to your project's classpath.
3. Convert Excel to JSON in Java — Step by Step
The conversion process involves four steps: loading the workbook, reading the header row, iterating through data rows, and assembling the JSON output. This section walks through each step and then presents the complete code.
Step 1: Load the Excel File
Use the Workbook class to open an Excel file. Then retrieve the target worksheet by index:
Workbook workbook = new Workbook();
workbook.loadFromFile("EmployeeData.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
Step 2: Read the Header Row
The first row of the spreadsheet typically contains column headers. These headers become the JSON keys for each record. Read them into a String array:
int columnCount = worksheet.getLastColumn();
String[] headers = new String[columnCount];
for (int col = 1; col <= columnCount; col++) {
headers[col - 1] = worksheet.get(1, col).getValue();
}
Step 3: Iterate Data Rows and Build JSON Objects
Starting from row 2, loop through each row and create an ObjectNode for every record. Each cell value is mapped to the corresponding header key:
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
for (int row = 2; row <= worksheet.getLastRow(); row++) {
ObjectNode record = mapper.createObjectNode();
for (int col = 1; col <= columnCount; col++) {
record.put(headers[col - 1], worksheet.get(row, col).getValue());
}
arrayNode.add(record);
}
Step 4: Export JSON Output
Use Jackson's ObjectMapper to write the ArrayNode to a file with pretty-print formatting:
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("EmployeeData.json"), arrayNode);
System.out.println("JSON exported successfully.");
} catch (IOException e) {
System.err.println("Failed to write JSON file: " + e.getMessage());
}
workbook.dispose();
Complete Code Example
Here is the full program that reads an Excel file and converts it to JSON:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.io.IOException;
public class ExcelToJsonConverter {
public static void main(String[] args) {
// Load the Excel workbook
Workbook workbook = new Workbook();
workbook.loadFromFile("EmployeeData.xlsx");
// Access the first worksheet
Worksheet worksheet = workbook.getWorksheets().get(0);
// Read column headers from the first row
int columnCount = worksheet.getLastColumn();
String[] headers = new String[columnCount];
for (int col = 1; col <= columnCount; col++) {
headers[col - 1] = worksheet.get(1, col).getValue();
}
// Create Jackson ObjectMapper and ArrayNode
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
// Convert each data row to a JSON object
for (int row = 2; row <= worksheet.getLastRow(); row++) {
ObjectNode record = mapper.createObjectNode();
for (int col = 1; col <= columnCount; col++) {
record.put(headers[col - 1], worksheet.get(row, col).getValue());
}
arrayNode.add(record);
}
// Write JSON output to file with pretty-print formatting
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("EmployeeData.json"), arrayNode);
System.out.println("Excel data converted to JSON successfully.");
} catch (IOException e) {
System.err.println("Error writing JSON file: " + e.getMessage());
}
// Release workbook resources
workbook.dispose();
}
}
Expected JSON output (for an Excel file with Name, Department, Email, and Salary columns):
[ {
"EmployeeID" : "E001",
"FirstName" : "John",
"LastName" : "Smith",
"Department" : "Engineering",
"Position" : "Software Engineer",
"Salary" : "85000",
"HireDate" : "2022/3/15 0:00:00"
} ]
The following diagram shows a visual comparison between the original Excel data and the converted JSON output for better understanding.

Key Spire.XLS Classes and Methods
- Workbook — Represents an Excel file. Handles loading, saving, and managing worksheets.
- Worksheet — Represents a single sheet within a workbook. Provides access to rows, columns, and cells.
get(int row, int column)— Returns aCellRangeobject for the specified cell. Row and column indices are 1-based.getValue()— Returns the cell's display value. UnlikegetText(), it correctly retrieves the value regardless of the cell's data type (text, number, date, etc.).getLastRow()/getLastColumn()— Return the last row and column numbers that contain data.
You can also learn how to convert Excel to CSV in Java for scenarios where a lightweight, tabular format is preferred for data exchange and storage.
4. Convert XLS and XLSX Files to JSON
Spire.XLS for Java supports both the legacy XLS format (Excel 97–2003) and the modern XLSX format (Excel 2007 and later). The library detects the file format automatically when you call loadFromFile(), so the same Java code converts XLS to JSON and XLSX to JSON without any modifications.
// Convert XLSX to JSON (modern format)
Workbook xlsxWorkbook = new Workbook();
xlsxWorkbook.loadFromFile("SalesReport.xlsx");
// Convert XLS to JSON (legacy format)
Workbook xlsWorkbook = new Workbook();
xlsWorkbook.loadFromFile("SalesReport.xls");
// Both workbooks are processed identically
Worksheet sheet = xlsxWorkbook.getWorksheets().get(0);
int rowCount = sheet.getLastRow();
int colCount = sheet.getLastColumn();
// ... same conversion logic as the basic example
No additional configuration, format flags, or separate code paths are needed. Whether you receive .xls files from legacy systems or .xlsx files from modern applications, Spire.XLS handles the parsing transparently. This is particularly useful in enterprise environments where Excel files may come from different sources and span multiple format generations.
You can also learn how to convert between XLS and XLSX formats in Java for scenarios where file format migration or legacy upgrade is required.
5. Handling Multi-Sheet Workbooks and Nested JSON
Real-world Excel workbooks often contain multiple worksheets. Converting each sheet to a separate JSON array produces a structured output that preserves the workbook's organization. In some cases, developers also need to build nested JSON objects that reflect hierarchical relationships within the data.
Convert Multiple Sheets to JSON
The following example reads all worksheets in a workbook and creates a JSON object where each key is the sheet name and each value is an array of records from that sheet:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.File;
import java.io.IOException;
public class MultiSheetExcelToJson {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("SalesReport.xlsx");
ObjectMapper mapper = new ObjectMapper();
ObjectNode fullReport = mapper.createObjectNode();
// Iterate through every worksheet in the workbook
for (int s = 0; s < workbook.getWorksheets().getCount(); s++) {
Worksheet worksheet = workbook.getWorksheets().get(s);
String sheetName = worksheet.getName();
// Read headers from the first row
int columnCount = worksheet.getLastColumn();
String[] headers = new String[columnCount];
for (int col = 1; col <= columnCount; col++) {
headers[col - 1] = worksheet.get(1, col).getValue();
}
// Convert data rows to JSON objects
ArrayNode sheetData = mapper.createArrayNode();
for (int row = 2; row <= worksheet.getLastRow(); row++) {
ObjectNode record = mapper.createObjectNode();
for (int col = 1; col <= columnCount; col++) {
record.put(headers[col - 1], worksheet.get(row, col).getValue());
}
sheetData.add(record);
}
// Add this sheet's data to the final output
fullReport.set(sheetName, sheetData);
}
// Write the combined JSON to file with pretty-print formatting
try {
mapper.writerWithDefaultPrettyPrinter().writeValue(new File("SalesReport.json"), fullReport);
System.out.println("Multi-sheet workbook converted to JSON.");
} catch (IOException e) {
System.err.println("Error writing JSON: " + e.getMessage());
}
workbook.dispose();
}
}
Output (for a workbook with "East Region" and "West Region" sheets):
{
"East Region": [
{"Employee": "Alice", "Product": "Laptop", "Amount": "1200"},
{"Employee": "Bob", "Product": "Monitor", "Amount": "450"}
],
"West Region": [
{"Employee": "Carol", "Product": "Keyboard", "Amount": "150"},
{"Employee": "Dave", "Product": "Mouse", "Amount": "75"}
]
}
The diagram below illustrates how multiple Excel sheets are mapped into a single JSON object structure.

Build Nested JSON from Excel Data
Some scenarios require nested JSON structures rather than flat arrays. For example, a project management spreadsheet might list projects and their tasks in adjacent columns. The following code groups tasks under their parent projects:
import com.spire.xls.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.LinkedHashMap;
import java.util.Map;
import java.io.File;
import java.io.IOException;
public class NestedExcelToJson {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("ProjectTasks.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
ObjectMapper mapper = new ObjectMapper();
// Use a LinkedHashMap to preserve project insertion order
Map<String, ObjectNode> projectMap = new LinkedHashMap<>();
for (int row = 2; row <= worksheet.getLastRow(); row++) {
String projectName = worksheet.get(row, 1).getValue();
String taskName = worksheet.get(row, 2).getValue();
String assignee = worksheet.get(row, 3).getValue();
String status = worksheet.get(row, 4).getValue();
// Create project entry on first encounter
if (!projectMap.containsKey(projectName)) {
ObjectNode project = mapper.createObjectNode();
project.put("name", projectName);
project.set("tasks", mapper.createArrayNode());
projectMap.put(projectName, project);
}
// Build task object and add to the project's task array
ObjectNode task = mapper.createObjectNode();
task.put("task", taskName);
task.put("assignee", assignee);
task.put("status", status);
((ArrayNode) projectMap.get(projectName).get("tasks")).add(task);
}
// Assemble final JSON array
ArrayNode projectsJson = mapper.createArrayNode();
for (ObjectNode project : projectMap.values()) {
projectsJson.add(project);
}
try {
mapper.writerWithDefaultPrettyPrinter()
.writeValue(new File("ProjectTasks.json"), projectsJson);
System.out.println("Nested JSON file generated successfully.");
} catch (IOException e) {
System.err.println("Error writing JSON file: " + e.getMessage());
}
workbook.dispose();
}
}
Output (for a project-task spreadsheet):
[
{
"name": "Website Redesign",
"tasks": [
{"task": "Design mockups", "assignee": "Alice", "status": "Complete"},
{"task": "Frontend implementation", "assignee": "Bob", "status": "In Progress"}
]
},
{
"name": "Mobile App",
"tasks": [
{"task": "API integration", "assignee": "Carol", "status": "Pending"},
{"task": "UI testing", "assignee": "Dave", "status": "Not Started"}
]
}
]
The following diagram shows how flat Excel rows are transformed into a nested JSON structure grouped by project.

This pattern is useful when Excel data needs to be restructured into a hierarchical format that matches an API schema or a database document model.
You can also explore how to parse Excel files in Java for scenarios where you need to extract and process raw spreadsheet data before transformation.
6. Handling Empty Cells and Data Types
Production Excel files rarely contain clean, complete data. Empty cells, mixed data types, and formatting inconsistencies are common. A robust Java program to convert Excel to JSON must account for these variations.
Detect and Handle Empty Cells
Use CellRange.getType() to check whether a cell is empty before reading its value. Provide a default value to prevent null entries in the JSON output:
CellRange cell = worksheet.get(row, col);
String value;
if (cell.getType() == CellValueType.Empty) {
value = ""; // or a default value like "N/A"
} else {
value = cell.getValue();
}
record.put(headers[col - 1], value);
Note: In Jackson,
ObjectNode.put(String, String)is used for string values. For other types, useput(String, double),put(String, boolean), etc.
Preserve Data Types in JSON Output
The getValue() method returns the cell's display value as a string. For numeric data, use getNumberValue() to preserve the original type in the JSON output:
CellRange cell = worksheet.get(row, col);
if (cell.getType() == CellValueType.Number) {
record.put(headers[col - 1], cell.getNumberValue().doubleValue());
} else if (cell.getType() == CellValueType.Boolean) {
record.put(headers[col - 1], cell.getBooleanValue());
} else {
record.put(headers[col - 1], cell.getValue());
}
Handle Date-Formatted Cells
Excel stores dates as serial numbers internally. To output dates as ISO 8601 strings in JSON, detect date formatting and convert accordingly:
CellRange cell = worksheet.get(row, col);
if (cell.getType() == CellValueType.DateTime) {
java.util.Date date = cell.getDateTimeValue();
java.text.SimpleDateFormat iso = new java.text.SimpleDateFormat("yyyy-MM-dd");
record.put(headers[col - 1], iso.format(date));
} else {
record.put(headers[col - 1], cell.getValue());
}
This approach ensures that dates appear in a standard format (e.g., "2026-07-02") rather than Excel's internal numeric representation.
7. Common Pitfalls
Skipping the Header Row
One of the most frequent mistakes is starting the data loop from row 1 instead of row 2. When the first row contains column headers, including it in the data loop produces a JSON object where the keys are duplicated as values.
Solution: Always read headers from row 1 first, then start the data loop from row 2.
Hardcoding Column Indices
Hardcoding column positions (e.g., worksheet.get(row, 1) for "Name") makes the code fragile. If the Excel template changes and columns are reordered, the JSON keys no longer match the intended data.
Solution: Read headers dynamically from the first row and use the header array to assign JSON keys. This way, column reordering does not break the conversion.
Number Precision Loss
Excel stores numbers as double-precision floating-point values. Using getValue() returns the display content of the cell, but the result is always a string. If the JSON output should contain raw numeric values (rather than strings), additional type conversion is needed.
Solution: Check the cell type with getType() and use getNumberValue() for numeric cells to get the actual numeric value instead of a string representation.
Ignoring Date Formatting
Excel represents dates as serial numbers (e.g., 45109 for June 15, 2023). While getValue() returns the display content of a date cell, the exact format depends on the cell's number format and may not be consistent across different workbooks.
Solution: Use getDateTimeValue() for cells with date formatting and convert the result to a standard ISO 8601 string (yyyy-MM-dd or yyyy-MM-dd'T'HH:mm:ss) for consistent JSON output.
Memory Leaks from Undisposed Workbooks
Spire.XLS workbook objects hold unmanaged resources. Failing to call dispose() after processing can lead to memory leaks, especially when converting multiple files in a batch.
Solution: Always call workbook.dispose() after the conversion is complete. Use a try-finally block to guarantee cleanup even if an exception occurs:
Workbook workbook = new Workbook();
try {
workbook.loadFromFile("EmployeeData.xlsx");
// ... conversion logic ...
} finally {
workbook.dispose();
}
8. Conclusion
In this article, we demonstrated how to convert Excel to JSON in Java using Spire.XLS for Java. Starting from a basic single-sheet conversion, we covered step-by-step workbook loading, header-based key mapping, and JSON output generation. We then extended the approach to handle XLS and XLSX formats, multi-sheet workbooks, nested JSON structures, empty cells, and data type preservation.
Spire.XLS for Java simplifies the entire process with a clean API that requires no Microsoft Office installation. Beyond Excel-to-JSON conversion, the library provides comprehensive spreadsheet capabilities including PDF export, chart creation, formula calculation, and data validation. You can apply for a 30-day free license to evaluate all features in your projects.
9. FAQ
How do I convert Excel to JSON in Java?
Load the Excel file using Spire.XLS for Java, read the header row to determine JSON keys, iterate through the data rows starting from row 2, and map each cell value to its corresponding key in a Jackson ObjectNode. Collect all objects into an ArrayNode and use ObjectMapper to write the result to a file or return it as a string. The complete code example is shown in Section 3.
Which Java library is best for Excel to JSON conversion?
Spire.XLS for Java provides a comprehensive API for reading Excel data with support for both XLS and XLSX formats. It handles cell types, formulas, and formatting natively, making it straightforward to extract structured data for JSON conversion without requiring Microsoft Office or any other external dependency.
Can Spire.XLS handle both XLS and XLSX formats?
Yes. Spire.XLS for Java automatically detects whether a file is in the legacy XLS format (Excel 97–2003) or the modern XLSX format (Excel 2007 and later). The same code works for both formats without any additional configuration. See Section 4 for details.
What is the difference between getValue() and getCellValue() in Spire.XLS?
getValue() returns the cell's display value — it works for all data types (text, number, date, boolean, etc.) and returns what the user sees in the cell. getCellValue() returns the raw underlying value as an Object. Use getValue() when the JSON output should match what users see in Excel, and use getNumberValue() or getBooleanValue() when you need typed values for numeric or boolean data.
How do I handle empty cells when converting Excel to JSON?
Check the cell type using CellRange.getType() before reading a value. If the type is CellValueType.Empty, assign a default value such as an empty string or "N/A". This prevents null entries and ensures consistent JSON structure across all records. See Section 6 for code examples.
Is Spire.XLS for Java free?
Spire.XLS for Java is a commercial library. A free version, Free Spire.XLS for Java, is available with limitations on worksheet count and features. You can also apply for a 30-day free license to evaluate the full feature set before purchasing.
Convert PDF to JSON in C#: Text, Tables, Forms & OCR

Your application receives a PDF invoice. You need the invoice number, vendor name, and line items — not as text on a page, but as structured JSON your API can consume. That is the real problem behind PDF to JSON conversion.
Unlike CSV or XML, a PDF file has no inherent data structure — no fields, no rows, no schema. Extracting usable JSON requires different approaches depending on what the document actually contains: plain text with key-value patterns, tables with rows and columns, fillable form fields, or scanned images that need OCR.
This article covers all four scenarios with runnable C# code using Spire.PDF for .NET. We build a real invoice-to-JSON converter, handle common table extraction problems like merged cells and missing headers, and package everything into a reusable PdfToJsonConverter class you can drop into any .NET project.
Quick Navigation
- What "PDF to JSON" Actually Means
- Install Spire.PDF for .NET
- Convert PDF Text to JSON in C#
- Convert PDF Tables to JSON in C#
- Convert PDF Form Fields to JSON
- Invoice PDF to JSON: A Real-World Example
- Convert Multiple PDFs to JSON in Batch
- Build a PDF to JSON Converter in C#
- Convert OCR Output to JSON in C#
- Performance Considerations
- FAQ
1. What "PDF to JSON" Actually Means
There is no built-in "PDF to JSON" conversion in the way you might convert a CSV to JSON. A PDF has no JSON structure. What developers actually need is: extract content from a PDF, then shape that content into a JSON format that matches their use case.
Depending on the PDF type and business requirement, the target JSON falls into one of three categories.
Raw Text JSON
Pull all text from each page and wrap it in a JSON envelope. Works for search indexing, RAG pipelines, and document archival.
{
"sourceFile": "Contract.pdf",
"pages": [
{ "pageNumber": 1, "text": "SERVICE AGREEMENT\nBetween Contoso Ltd and..." }
]
}
Key-Value JSON
Many PDFs follow a Label: Value pattern — employee records, registration forms, simple invoices. The goal here is to parse those pairs into a flat JSON object:
{
"name": "John Smith",
"email": "john@contoso.com",
"department": "Engineering",
"employeeId": "EMP-2026-0142"
}
Structured Business JSON
Real business documents have nested data: an invoice has a header, line items, tax breakdowns, and payment terms. The JSON output needs to mirror that structure:
{
"invoiceNumber": "INV-2026-0042",
"vendor": "Contoso Ltd",
"date": "2026-06-15",
"lineItems": [
{ "description": "Widget A", "quantity": 150, "unitPrice": 24.50, "total": 3675.00 }
],
"subtotal": 3675.00,
"tax": 294.00,
"total": 3969.00
}
This distinction matters. When you search for "convert PDF to JSON," you need to decide which output format your application requires. The rest of this article shows how to build each one using Spire.PDF in C#.
2. Install Spire.PDF for .NET
Install via NuGet Package Manager Console:
Install-Package Spire.PDF
Or add to your .csproj:
<PackageReference Include="Spire.PDF" Version="*" />
Include these namespaces in your project:
using Spire.Pdf;
using Spire.Pdf.Texts;
using Spire.Pdf.Utilities;
using Spire.Pdf.Fields;
using Spire.Pdf.Widget;
using System.Text.Json;
using System.Text.Json.Serialization;
Spire.PDF supports .NET Framework, .NET Core, and .NET 6/7/8/9+.
3. Convert PDF Text to JSON in C#
The most common starting point: extract text from a PDF and produce JSON output.
Extract Text from PDF
using Spire.Pdf;
using Spire.Pdf.Texts;
using System.Collections.Generic;
using (PdfDocument pdf = new PdfDocument())
{
pdf.LoadFromFile("EmployeeRecord.pdf");
var pages = new List<Dictionary<string, string>>();
for (int i = 0; i < pdf.Pages.Count; i++)
{
PdfPageBase page = pdf.Pages[i];
PdfTextExtractOptions options = new PdfTextExtractOptions();
options.IsExtractAllText = true;
PdfTextExtractor extractor = new PdfTextExtractor(page);
string pageText = extractor.ExtractText(options);
pages.Add(new Dictionary<string, string>
{
{ "pageNumber", (i + 1).ToString() },
{ "text", pageText.Trim() }
});
}
}
Parse Key-Value Pairs into JSON
If your PDF follows a Label: Value pattern, parse the extracted text into structured fields:
using System.Text.Json;
var parsedFields = new Dictionary<string, string>();
foreach (var page in pages)
{
string[] lines = page["text"].Split('\n');
foreach (string line in lines)
{
int colonIndex = line.IndexOf(':');
if (colonIndex > 0)
{
string key = line.Substring(0, colonIndex).Trim();
string value = line.Substring(colonIndex + 1).Trim();
parsedFields[key] = value;
}
}
}
var jsonOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
string jsonOutput = JsonSerializer.Serialize(parsedFields, jsonOptions);
File.WriteAllText("EmployeeRecord.json", jsonOutput);
Key API Calls
PdfDocument.LoadFromFile()— opens the PDF filePdfTextExtractor.ExtractText()— extracts text content from a pagePdfTextExtractOptions.IsExtractAllText— preserves whitespace and formatting
Output
The following example shows the structured JSON generated from the extracted employee record.
{
"name": "John Smith",
"email": "john.smith@contoso.com",
"department": "Engineering",
"employeeId": "EMP-2026-0142",
"startDate": "2024-03-15"
}
The following screenshot shows the actual JSON file generated after running the example.

This approach works well for forms, records, and documents with consistent key-value layouts. For unstructured text, skip the parsing step and serialize the raw pages directly.
If you need a deeper look at PDF text extraction, see our dedicated guide on extracting text from PDFs in C# using Spire.PDF for .NET.
4. Convert PDF Tables to JSON in C#
The previous section focused on extracting plain text from PDFs. While that works well for paragraphs and simple records, many business documents organize their most valuable information in tables, such as invoice line items, sales reports, and financial statements. To preserve rows, columns, and relationships between cells, table data must be extracted differently before it can be converted into structured JSON.
Why Table Extraction Is Different from Text Extraction
Text extraction returns a flat stream of characters in reading order. Although a table may appear perfectly organized on the page, the extracted text often loses its row-and-column structure, making it difficult to identify which values belong together.
To preserve the table layout, you need a dedicated table extraction engine. PdfTableExtractor analyzes the page layout, detects table boundaries, and returns PdfTable objects that you can iterate row by row and cell by cell. Instead of producing a flat string such as:
Widget A 150 $24.50 $3,675.00
it enables you to generate structured JSON like:
{
"Product": "Widget A",
"Quantity": "150",
"Unit Price": "$24.50",
"Total": "$3,675.00"
}
The following example demonstrates how to extract tables from a PDF and serialize them into JSON.
Extract Tables from PDF
using Spire.Pdf;
using Spire.Pdf.Utilities;
using System.Collections.Generic;
using (PdfDocument pdf = new PdfDocument())
{
pdf.LoadFromFile("SalesReport.pdf");
PdfTableExtractor tableExtractor = new PdfTableExtractor(pdf);
var allTables = new List<List<List<string>>>();
for (int pageIndex = 0; pageIndex < pdf.Pages.Count; pageIndex++)
{
PdfTable[] tables = tableExtractor.ExtractTable(pageIndex);
if (tables != null && tables.Length > 0)
{
foreach (PdfTable table in tables)
{
int rowCount = table.GetRowCount();
int colCount = table.GetColumnCount();
var tableData = new List<List<string>>();
for (int row = 0; row < rowCount; row++)
{
var rowData = new List<string>();
for (int col = 0; col < colCount; col++)
{
rowData.Add(table.GetText(row, col).Trim());
}
tableData.Add(rowData);
}
allTables.Add(tableData);
}
}
}
}
Serialize Table Data to JSON
var jsonTables = new List<object>();
foreach (var tableData in allTables)
{
if (tableData.Count < 2) continue;
var headers = tableData[0];
var rows = new List<Dictionary<string, string>>();
for (int i = 1; i < tableData.Count; i++)
{
var rowObj = new Dictionary<string, string>();
for (int j = 0; j < headers.Count && j < tableData[i].Count; j++)
{
rowObj[headers[j]] = tableData[i][j];
}
rows.Add(rowObj);
}
jsonTables.Add(new
{
tableIndex = allTables.IndexOf(tableData) + 1,
headers = headers,
data = rows
});
}
string tableJson = JsonSerializer.Serialize(new
{
sourceFile = "SalesReport.pdf",
tables = jsonTables
}, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText("SalesReport_Tables.json", tableJson);
Key API Calls
PdfTableExtractor(PdfDocument)— initializes the table extraction enginePdfTableExtractor.ExtractTable(pageIndex)— detects and extracts tables from a pagePdfTable.GetRowCount()/GetColumnCount()— returns table dimensionsPdfTable.GetText(row, col)— reads cell content
Sample JSON Output
The resulting JSON preserves the original table structure by organizing each row into key-value pairs based on the detected column headers.
{
"sourceFile": "SalesReport.pdf",
"tables": [
{
"tableIndex": 1,
"headers": ["Product", "Quantity", "Unit Price", "Total"],
"data": [
{ "Product": "Widget A", "Quantity": "150", "Unit Price": "$24.50", "Total": "$3,675.00" },
{ "Product": "Widget B", "Quantity": "80", "Unit Price": "$39.90", "Total": "$3,192.00" }
]
}
]
}
The following screenshot shows the actual JSON file generated after running the example.

This approach works well for invoices, reports, and other PDFs with well-defined table structures. For documents containing merged cells, missing headers, or multi-page tables, additional post-processing may be required.
If you need a deeper look at PDF table extraction, see our dedicated guide on extracting tables from PDFs in C# using Spire.PDF for .NET.
Common Table Extraction Problems
Real-world PDF tables are messy. Here are the three problems you will hit most often, and how to handle them.
Problem 1: Missing Headers
Many invoices and reports have tables without explicit header rows. The data starts immediately:
Apple 10 $2.99 $29.90
Orange 5 $1.50 $7.50
When the first row is data rather than headers, assign column names manually based on your known schema:
// Define headers when the PDF table has no header row
string[] defaultHeaders = { "Product", "Quantity", "UnitPrice", "Total" };
var rows = new List<Dictionary<string, string>>();
for (int i = 0; i < tableData.Count; i++) // Start from 0, not 1
{
var rowObj = new Dictionary<string, string>();
for (int j = 0; j < defaultHeaders.Length && j < tableData[i].Count; j++)
{
rowObj[defaultHeaders[j]] = tableData[i][j];
}
rows.Add(rowObj);
}
Problem 2: Merged Cells
Tables in financial reports often have merged cells for grouping:
Quarter Revenue Expenses
Q1 $120,000 $95,000
$115,000 $88,000
Q2 $140,000 $102,000
The extractor returns empty strings for merged cells. Fill them forward from the last non-empty value:
// Fill merged cells with the previous row's value
for (int col = 0; col < headers.Count; col++)
{
string lastValue = "";
for (int row = 1; row < tableData.Count; row++)
{
if (col < tableData[row].Count && !string.IsNullOrWhiteSpace(tableData[row][col]))
{
lastValue = tableData[row][col];
}
else if (col < tableData[row].Count)
{
tableData[row][col] = lastValue;
}
}
}
Problem 3: Multi-Page Tables
Enterprise reports often have a single table spanning multiple pages, with the header row repeated on each page. Handle this by deduplicating headers during serialization:
var combinedRows = new List<Dictionary<string, string>>();
string[] expectedHeaders = null;
for (int pageIndex = 0; pageIndex < pdf.Pages.Count; pageIndex++)
{
PdfTable[] tables = tableExtractor.ExtractTable(pageIndex);
if (tables == null) continue;
foreach (PdfTable table in tables)
{
for (int r = 0; r < table.GetRowCount(); r++)
{
var cells = new List<string>();
for (int c = 0; c < table.GetColumnCount(); c++)
{
cells.Add(table.GetText(r, c).Trim());
}
// First row of first page becomes the headers
if (expectedHeaders == null && r == 0)
{
expectedHeaders = cells.ToArray();
continue;
}
// Skip repeated header rows on subsequent pages
if (r == 0 && cells.SequenceEqual(expectedHeaders))
continue;
var rowDict = new Dictionary<string, string>();
for (int c = 0; c < expectedHeaders.Length && c < cells.Count; c++)
{
rowDict[expectedHeaders[c]] = cells[c];
}
combinedRows.Add(rowDict);
}
}
}
5. Convert PDF Form Fields to JSON
Unlike plain text or tables, fillable PDF forms already store data as named fields. Applications, surveys, and registration forms contain field names and values that can be mapped directly to JSON key-value pairs, making form data one of the easiest types of PDF content to serialize.
Read and Export Form Fields
using Spire.Pdf;
using Spire.Pdf.Fields;
using Spire.Pdf.Widget;
using System.Collections.Generic;
using (PdfDocument pdf = new PdfDocument())
{
pdf.LoadFromFile("RegistrationForm.pdf");
PdfFormWidget formWidget = pdf.Form as PdfFormWidget;
var formData = new Dictionary<string, object>();
if (formWidget != null)
{
for (int i = 0; i < formWidget.FieldsWidget.List.Count; i++)
{
PdfField field = formWidget.FieldsWidget.List[i] as PdfField;
if (field is PdfTextBoxFieldWidget textBox)
formData[textBox.Name] = textBox.Text;
else if (field is PdfCheckBoxWidgetFieldWidget checkBox)
formData[checkBox.Name] = checkBox.Checked;
else if (field is PdfRadioButtonListFieldWidget radioButton)
formData[radioButton.Name] = radioButton.Value;
else if (field is PdfComboBoxWidgetFieldWidget comboBox)
formData[comboBox.Name] = comboBox.SelectedValue;
else if (field is PdfListBoxWidgetFieldWidget listBox)
{
var selectedItems = new List<string>();
foreach (PdfListWidgetItem item in listBox.Values)
selectedItems.Add(item.Value);
formData[listBox.Name] = selectedItems;
}
}
}
var formOutput = new
{
sourceFile = "RegistrationForm.pdf",
fieldCount = formData.Count,
fields = formData
};
string json = JsonSerializer.Serialize(formOutput, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText("RegistrationForm_Data.json", json);
}
Key API Calls
PdfFormWidget— provides access to the document's interactive formPdfTextBoxFieldWidget.Text— reads text input valuesPdfCheckBoxWidgetFieldWidget.Checked— reads checkbox statePdfRadioButtonListFieldWidget.Value— reads selected radio buttonPdfComboBoxWidgetFieldWidget.SelectedValue— reads combo box selection
Output
The following example shows how the extracted form fields are represented as structured JSON.
{
"sourceFile": "RegistrationForm.pdf",
"fieldCount": 6,
"fields": {
"FullName": "John Smith",
"Email": "john.smith@contoso.com",
"Department": "Sales",
"AgreeTerms": true,
"SubscriptionPlan": "Enterprise",
"Skills": ["C#", "SQL", "Azure"]
}
}
The following screenshot shows the actual JSON file generated after exporting the form data.

This approach works well for interactive PDF forms that contain structured fields such as text boxes, check boxes, radio buttons, and drop-down lists. Because each field already has a unique name, the extracted data can be serialized directly into JSON without additional parsing.
If you need a deeper look at importing and exporting PDF form field data in C#, see our dedicated guide on working with PDF form fields using Spire.PDF for .NET.
6. Invoice PDF to JSON: A Real-World Example
Invoice processing is one of the most common business use cases for PDF to JSON conversion. Instead of presenting a full parser implementation, this section demonstrates how the extraction techniques from Sections 3 and 4 come together to solve a real problem.
Target JSON Structure
Before writing any extraction code, define your target schema. For a typical invoice, the JSON output might look like this:
{
"invoiceNumber": "INV-2026-0042",
"date": "2026-06-15",
"vendor": "Contoso Ltd",
"paymentTerms": "Net 30",
"lineItems": [
{ "description": "Widget A", "quantity": 150, "unitPrice": 24.50, "total": 3675.00 },
{ "description": "Widget B", "quantity": 80, "unitPrice": 39.90, "total": 3192.00 }
],
"subtotal": 8367.00,
"tax": 669.36,
"total": 9036.36
}
Extraction Pattern
Use text extraction (Section 3) to parse header fields via regex, and table extraction (Section 4) to pull line items:
// Parse header fields from extracted text using regex
invoice["invoiceNumber"] = Regex.Match(fullText, @"Invoice Number:\s*(\S+)").Groups[1].Value;
invoice["date"] = Regex.Match(fullText, @"Date:\s*(\S+)").Groups[1].Value;
invoice["vendor"] = Regex.Match(fullText, @"Vendor:\s*(.+)").Groups[1].Value;
// Extract line items from table data (Section 4 pattern)
for (int r = 1; r < table.GetRowCount(); r++)
{
lineItems.Add(new
{
description = table.GetText(r, 0).Trim(),
quantity = int.Parse(table.GetText(r, 1).Trim()),
unitPrice = ParseCurrency(table.GetText(r, 2)),
total = ParseCurrency(table.GetText(r, 3))
});
}
The implementation combines the text extraction introduced in Section 3 with the table extraction introduced in Section 4. Regex is used only for simple field matching — the core PDF processing relies entirely on Spire.PDF APIs.
Handling Different Invoice Layouts
In production, you rarely deal with a single invoice format:
- Fixed template + regex — works when you control the source or process invoices from a known vendor
- Template matching — maintain a set of regex patterns, one per vendor
- AI-assisted extraction — for unknown or highly variable layouts, combine OCR output with an LLM
Regex-based parsing is fast and reliable for known formats. For a production-ready implementation, extend the PdfToJsonConverter class from Section 8 to build a dedicated invoice parser that reuses the same extraction patterns.
7. Convert Multiple PDFs to JSON in Batch
Production workflows process hundreds or thousands of PDFs at once. This batch processor handles errors gracefully and logs results:
using Spire.Pdf;
using Spire.Pdf.Texts;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
string inputDir = @"C:\PDFs\Invoices";
string outputDir = @"C:\Output\JSON";
Directory.CreateDirectory(outputDir);
string[] pdfFiles = Directory.GetFiles(inputDir, "*.pdf");
var results = new List<object>();
foreach (string pdfPath in pdfFiles)
{
string fileName = Path.GetFileNameWithoutExtension(pdfPath);
string outputPath = Path.Combine(outputDir, $"{fileName}.json");
try
{
using (PdfDocument pdf = new PdfDocument())
{
pdf.LoadFromFile(pdfPath);
var pageTexts = new List<string>();
for (int i = 0; i < pdf.Pages.Count; i++)
{
var extractor = new PdfTextExtractor(pdf.Pages[i]);
var options = new PdfTextExtractOptions { IsExtractAllText = true };
pageTexts.Add(extractor.ExtractText(options).Trim());
}
var doc = new
{
sourceFile = Path.GetFileName(pdfPath),
pageCount = pdf.Pages.Count,
processedAt = DateTime.UtcNow,
content = pageTexts
};
File.WriteAllText(outputPath, JsonSerializer.Serialize(doc,
new JsonSerializerOptions { WriteIndented = true }));
results.Add(new { file = fileName, status = "success" });
}
}
catch (Exception ex)
{
results.Add(new { file = fileName, status = "error", error = ex.Message });
}
}
File.WriteAllText(Path.Combine(outputDir, "_log.json"),
JsonSerializer.Serialize(results, new JsonSerializerOptions { WriteIndented = true }));
Swap the text-only extraction with the invoice JSON extraction pattern from Section 6 if your batch consists of invoices, or with the PdfToJsonConverter class from Section 8 for general-purpose conversion.
8. Build a PDF to JSON Converter in C#
For production applications, encapsulate all extraction logic into a single class. The PdfToJsonConverter below combines text, table, and form field extraction into one reusable PDF to JSON converter:
using Spire.Pdf;
using Spire.Pdf.Texts;
using Spire.Pdf.Utilities;
using Spire.Pdf.Fields;
using Spire.Pdf.Widget;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
public class PdfToJsonConverter
{
private readonly JsonSerializerOptions _jsonOptions = new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
public string ConvertToJson(string pdfPath)
{
using (PdfDocument pdf = new PdfDocument())
{
pdf.LoadFromFile(pdfPath);
var result = new
{
sourceFile = Path.GetFileName(pdfPath),
processedAt = DateTime.UtcNow,
text = ExtractText(pdf),
tables = ExtractTables(pdf),
formFields = ExtractFormFields(pdf)
};
return JsonSerializer.Serialize(result, _jsonOptions);
}
}
public void ConvertAndSave(string pdfPath, string outputPath)
{
File.WriteAllText(outputPath, ConvertToJson(pdfPath));
}
// Reuses the text extraction technique from Section 3 (PdfTextExtractor + PdfTextExtractOptions)
private List<PageText> ExtractText(PdfDocument pdf) { return new List<PageText>(); }
// Reuses the table extraction technique from Section 4 (PdfTableExtractor + ExtractTable)
private List<TableData> ExtractTables(PdfDocument pdf) { return new List<TableData>(); }
// Reuses the form field extraction technique from Section 5 (PdfFormWidget + field type checking)
private Dictionary<string, object> ExtractFormFields(PdfDocument pdf) { return new Dictionary<string, object>(); }
}
public class PageText
{
public int PageNumber { get; set; }
public string Text { get; set; }
}
public class TableData
{
public int PageNumber { get; set; }
public int RowCount { get; set; }
public List<List<string>> Rows { get; set; }
}
Usage
var converter = new PdfToJsonConverter();
// Single file
converter.ConvertAndSave("InvoiceReport.pdf", "InvoiceReport.json");
// Use inside an ASP.NET controller
[HttpPost("api/pdf-to-json")]
public IActionResult ConvertPdf(IFormFile file)
{
var tempPath = Path.GetTempFileName();
file.CopyTo(new FileStream(tempPath, FileMode.Create));
var converter = new PdfToJsonConverter();
string json = converter.ConvertToJson(tempPath);
return Content(json, "application/json");
}
The helper methods (ExtractText, ExtractTables, ExtractFormFields) reuse the extraction techniques introduced in Sections 3–5. Refer to those sections for the full implementations.
Best Practices for Production Pipelines
When building PDF to JSON conversion into a production system:
- Define your JSON schema first. Map each PDF element to a target field before writing extraction code.
- Validate extracted data. Currency strings, dates, and IDs should be parsed and verified before serialization.
- Handle missing values. Use
JsonIgnoreCondition.WhenWritingNullto omit null fields from output. - Include metadata. Always record source file name, page numbers, and extraction timestamp for auditing.
- Clean text artifacts. Trim whitespace, normalize line breaks, and handle encoding issues in extracted strings.
9. Convert OCR Output to JSON in C#
Scanned PDFs contain images rather than selectable text, so they must be processed with an OCR engine before they can be converted to JSON. Spire.PDF handles PDF rendering and page processing, while text recognition should be performed by an OCR solution such as Tesseract or Azure AI Vision.
For a complete walkthrough, see How to Extract Text from Scanned PDFs in C#.
Once OCR returns the recognized text, you can parse it using the same techniques shown earlier in this article.
Parse OCR Text into JSON
string recognizedText = ocrEngine.Recognize(imagePath);
// Parse recognized text using the same helper methods demonstrated in previous examples.
var parsedData = ParseRecognizedText(recognizedText);
string json = JsonSerializer.Serialize(parsedData, new JsonSerializerOptions
{
WriteIndented = true
});
Best Practices
- Scan documents at 300 DPI or higher for better OCR accuracy.
- Validate important fields such as invoice numbers, dates, and currency values before serialization.
- Reuse the parsing patterns introduced earlier in this article to build consistent JSON structures.
10. Performance Considerations
PDF to JSON conversion works fine for a single 5-page document. In production, you are processing hundreds of files with hundreds of pages each. These are the issues you will actually hit.
Large PDFs (100+ Pages)
Avoid loading all page text into a List<string> before serialization. Process and write each page incrementally:
using (var stream = File.Create("output.json"))
using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }))
{
writer.WriteStartObject();
writer.WriteString("sourceFile", Path.GetFileName(pdfPath));
writer.WriteStartArray("pages");
for (int i = 0; i < pdf.Pages.Count; i++)
{
var extractor = new PdfTextExtractor(pdf.Pages[i]);
var options = new PdfTextExtractOptions { IsExtractAllText = true };
string text = extractor.ExtractText(options).Trim();
writer.WriteStartObject();
writer.WriteNumber("pageNumber", i + 1);
writer.WriteString("text", text);
writer.WriteEndObject();
}
writer.WriteEndArray();
writer.WriteEndObject();
}
Utf8JsonWriter writes directly to the stream instead of building a string in memory. For a 500-page document, this can cut peak memory usage by 60-70% compared to JsonSerializer.Serialize().
Memory Usage
PdfDocument holds parsed page trees, fonts, and image references in memory. Two rules:
- Always wrap
PdfDocumentinusing— it releases unmanaged resources on dispose - Process one document at a time — do not keep multiple
PdfDocumentinstances open simultaneously unless you have the RAM for it
For batch jobs processing 1000+ files, the using pattern inside the loop ensures each document is fully released before the next one loads.
Parallel Processing
Batch conversion is CPU-bound and parallelizes well:
var pdfFiles = Directory.GetFiles(inputDir, "*.pdf");
Parallel.ForEach(pdfFiles,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
pdfPath =>
{
string outputPath = Path.Combine(outputDir,
Path.GetFileNameWithoutExtension(pdfPath) + ".json");
var converter = new PdfToJsonConverter();
converter.ConvertAndSave(pdfPath, outputPath);
});
Each thread creates its own PdfToJsonConverter and PdfDocument instance. PdfDocument is not thread-safe — never share a single instance across threads.
When to Use Streaming JSON
Use Utf8JsonWriter over JsonSerializer.Serialize() when:
- Output JSON exceeds 50 MB
- You are processing PDFs with 200+ pages
- Running in a memory-constrained environment (container with 512 MB limit)
For smaller documents, JsonSerializer is simpler and the memory difference is negligible.
11. FAQ
Can I convert PDF to JSON in C# for free?
Spire.PDF for .NET offers a free evaluation version with a page limit. For production use, you can apply for a 30-day free license or purchase a commercial license. The System.Text.Json serializer is built into .NET and free.
Can scanned PDFs be converted to JSON?
Yes, but you need an external OCR engine. Spire.PDF renders PDF pages as images via SaveAsImage(), which you then pass to Tesseract, Azure Computer Vision, or Amazon Textract for text recognition. The recognized text is then parsed and serialized to JSON. See Section 9 for the integration pattern.
Can I convert PDF tables to JSON automatically?
Yes. PdfTableExtractor automatically detects table structures on each page without manual configuration. It handles both properly structured tables (created in Word or Excel) and visual tables (text aligned to look like rows and columns). For multi-page tables or tables without headers, see the handling patterns in Section 4.
Can I batch convert multiple PDFs to JSON?
Yes. Iterate through a directory using Directory.GetFiles(), process each PDF with Spire.PDF extraction APIs, and save individual JSON files. Include error handling so one failed file does not stop the batch. See Section 7 for a complete example.
How can I convert large PDF files to JSON in C#?
Process the PDF page-by-page rather than loading all content into memory at once. For very large files (100+ pages), use Utf8JsonWriter to write JSON incrementally to a stream instead of building the entire output in memory. See Section 10 for the streaming JSON pattern and parallel processing approach.
Can I convert PDF to JSON using an API?
Yes. You can wrap the PdfToJsonConverter class from this article in an ASP.NET Web API endpoint. Accept a PDF upload, run the extraction, and return the JSON response. Spire.PDF works in any .NET hosting environment — ASP.NET Core, Azure Functions, AWS Lambda, or a self-hosted console app. See the ASP.NET controller example in Section 8.
Conclusion
PDF to JSON is not a single operation. Depending on your document, you are solving one of three different problems: wrapping raw text in a JSON envelope, parsing key-value patterns into flat objects, or building structured business JSON from text and table extraction.
This article covered all three, plus the complications that break naive implementations: tables without headers, merged cells, multi-page tables, fillable form fields, varying invoice layouts, batch processing, memory management for large documents, and OCR integration boundaries.
The PdfToJsonConverter class is a starting point you can adapt to your document types. The invoice extraction pattern shown in Section 6 demonstrates how to combine these techniques for real business documents. Both use Spire.PDF for .NET, which handles all PDF reading locally without external dependencies.
To get started:
- Install via NuGet:
Install-Package Spire.PDF - Apply for a 30-day free license to evaluate without page limits
- Explore the Spire.PDF documentation for additional extraction scenarios
How to Convert Word to JSON in Python (DOCX to JSON)

Converting Word documents to JSON is a common requirement when building automated document processing pipelines, feeding content into AI models, or migrating structured data from DOCX files into databases and APIs. Unlike CSV or XML, JSON provides a flexible, hierarchical format that can represent paragraphs, tables, and nested document structures in a single output.
However, Word files do not have a native JSON export format. A .docx file is a rich-text document composed of sections, paragraphs, styles, and tables—not a structured data source. Converting it to JSON requires deciding how to map that content into a meaningful schema.
This tutorial demonstrates how to convert Word to JSON in Python using Spire.Doc for Python. You will learn three progressively advanced methods: extracting plain paragraph text, converting Word tables to JSON arrays, and preserving the full document structure—including headings, paragraphs, and tables—in a hierarchical JSON output. The examples in this tutorial work with both DOCX and legacy DOC files supported by Spire.Doc.
Quick Navigation
- How Is Word Converted into JSON?
- Install the Required Library
- Method 1 – Convert Word Text to JSON
- Method 2 – Convert Word Tables to JSON
- Method 3 – Preserve Document Structure in JSON
- When to Use Word to JSON Conversion
- Limitations and Best Practices
- FAQ
- Conclusion
1. How Is Word Converted into JSON?
A Word document is a rich-text format organized into sections, paragraphs, and tables—not a structured data format. When you convert Word to JSON, there is no single standard for how the content should be represented. The right schema depends on how the JSON will be used:
| Goal | Recommended Schema | Key Characteristics |
|---|---|---|
| AI embedding / semantic search | Paragraph array | Flat list of text strings, one per paragraph |
| Full-text search indexing | Text blocks with metadata | Paragraphs with section index and style info |
| Database import from tables | Table row objects | Header-keyed dictionaries, one per row |
| RAG pipeline / knowledge base | Hierarchical structure | Nested sections with headings, paragraphs, and tables |
| Document archival / interchange | Full document model | Sections, styles, metadata, and all content types |
For example, a Word document containing a heading and a paragraph could be represented in JSON as:
{
"document": [
{"type": "heading", "level": 1, "text": "Project Overview"},
{"type": "paragraph", "text": "This report summarizes the quarterly results."}
]
}
The three methods in this tutorial correspond directly to these schema choices:
- Method 1 produces a paragraph array (AI embedding, search indexing)
- Method 2 produces table row objects (database import, data extraction)
- Method 3 produces a hierarchical structure (RAG, knowledge base, document understanding)
Choose the method that matches your goal, or combine elements from multiple methods to build a custom schema.
2. Install the Required Library
This tutorial uses Spire.Doc for Python to read and parse DOC/DOCX files. Install it via pip:
pip install spire.doc
Alternatively, you can download Spire.Doc for Python and integrate it manually.
After installation, import the library in your Python script:
from spire.doc import Document, FileFormat
from spire.doc.common import *
Spire.Doc provides APIs to load Word documents, iterate through sections, paragraphs, and tables, and extract text content—everything needed to build a Word-to-JSON pipeline.
3. Method 1 – Convert Word Text to JSON
The simplest way to convert Word to JSON is to extract all paragraph text from the document and store it in a JSON array. This approach works well when you need the full text content without structural metadata—such as for full-text search, AI text embedding, or simple content export.
3.1 Read Paragraphs from a Word Document
Spire.Doc represents a Word document as a collection of Sections, each containing Paragraphs. To extract all text, you iterate through every section and every paragraph within it.
from spire.doc import Document
from spire.doc.common import *
input_file = "ProjectReport.docx"
document = Document()
document.LoadFromFile(input_file)
paragraphs = []
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for j in range(section.Paragraphs.Count):
paragraph = section.Paragraphs.get_Item(j)
text = paragraph.Text
if text.strip():
paragraphs.append(text)
document.Close()
Each paragraph's .Text property returns the plain text content, stripping away formatting. The if text.strip() check filters out empty paragraphs that exist as spacing or layout elements in Word.
3.2 Serialize the Extracted Text to JSON
Assuming the paragraph data extracted in the previous step is stored in the paragraphs list, you can serialize it to JSON and save it to a file as follows:
import json
output_file = "paragraphs.json"
result = {
"source": input_file,
"paragraph_count": len(paragraphs),
"paragraphs": paragraphs
}
with open(output_file, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
Output Example
The following JSON snippet shows the structure of the generated output file:
{
"source": "ProjectReport.docx",
"paragraph_count": 3,
"paragraphs": [
"Quarterly Sales Report",
"This document provides an overview of sales performance across all regions."
]
}
Conversion Result
The image below shows the source Word document and the JSON file generated after extracting paragraph text.

3.3 Explanation
Why iterate through Sections and Paragraphs instead of extracting all text at once? Because Word documents are organized hierarchically. A document contains one or more sections (each with its own page layout), and each section contains paragraphs. Iterating at this level gives you control over which content to include or skip—such as filtering empty paragraphs or limiting extraction to specific sections.
Storing paragraphs as a JSON array is the most straightforward structure. Each element is a string, making the output easy to consume in downstream systems. This approach is well-suited for:
- Full-text indexing – feed paragraph text into search engines like Elasticsearch
- AI text embedding – convert paragraphs into vector representations for semantic search
- Simple content export – extract readable text from Word files without formatting
However, this method loses structural information. Headings, body text, and list items are all treated the same way. If you need to distinguish between them, see Method 3.
If your goal is simply to extract text content from Word documents without converting it to JSON, you may also be interested in our guide on extracting text from Word documents in Python.
4. Method 2 – Convert Word Tables to JSON
In many Word documents—reports, invoices, product lists, configuration tables—the most valuable content lives inside tables, not in paragraphs. Converting Word tables to JSON allows you to extract structured row-and-column data that can be directly loaded into databases, APIs, or data analysis tools.
Why Tables Need Special Handling
Tables in Word are stored as a grid of rows and cells, where each cell contains its own paragraphs. Unlike paragraph text, table data has an inherent two-dimensional structure that maps naturally to JSON objects. The first row often contains column headers, and subsequent rows contain data records.
Extracting Tables from a Word Document
The following code reads all tables from a Word document, uses the first row as column headers, and converts each subsequent row into a JSON object:
import json
from spire.doc import Document
from spire.doc.common import *
input_file = "SalesData.docx"
output_file = "tables.json"
document = Document()
document.LoadFromFile(input_file)
all_tables = []
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
for t in range(section.Tables.Count):
table = section.Tables.get_Item(t)
rows_data = []
if table.Rows.Count < 2:
continue
header_row = table.Rows[0]
headers = []
for c in range(header_row.Cells.Count):
cell_text = header_row.Cells[c].Paragraphs[0].Text.strip()
headers.append(cell_text)
for r in range(1, table.Rows.Count):
row = table.Rows[r]
row_dict = {}
for c in range(row.Cells.Count):
cell_text = row.Cells[c].Paragraphs[0].Text.strip()
row_dict[headers[c] if c < len(headers) else f"Column_{c}"] = cell_text
rows_data.append(row_dict)
all_tables.append({
"table_index": t,
"headers": headers,
"row_count": len(rows_data),
"rows": rows_data
})
document.Close()
result = {
"source": input_file,
"table_count": len(all_tables),
"tables": all_tables
}
with open(output_file, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
Output Example
The following JSON snippet shows the structure of the generated output file, with each table row mapped to a JSON object using the header row as keys:
{
"source": "SalesData.docx",
"table_count": 1,
"tables": [
{
"table_index": 0,
"headers": ["Region", "Product", "Units Sold", "Revenue"],
"row_count": 3,
"rows": [
{"Region": "North", "Product": "Laptop", "Units Sold": "120", "Revenue": "114000"},
{"Region": "South", "Product": "Laptop", "Units Sold": "80", "Revenue": "76000"}
]
}
]
}
Conversion Result
The image below demonstrates how table data from a Word document is converted into structured JSON records.

Explanation
The code treats the first row as a header row and maps each cell in subsequent rows to the corresponding header key. This produces a JSON array of objects, which is the most common and useful format for tabular data.
Key considerations:
table.Rows.Count < 2skips tables that have only a header row or are emptyrow.Cells[c].Paragraphs[0].Textextracts text from the first paragraph in each cell. For simplicity, the example reads only the first paragraph. If a cell contains multiple paragraphs, iterate through the entireParagraphscollection and concatenate the results:
cell_text = "\n".join(
row.Cells[c].Paragraphs[p].Text.strip()
for p in range(row.Cells[c].Paragraphs.Count)
if row.Cells[c].Paragraphs[p].Text.strip()
)
headers[c] if c < len(headers) else f"Column_{c}"handles cases where a data row has more cells than the header row
This method is ideal for extracting structured data from reports, invoices, product catalogs, and configuration tables stored in Word documents. The resulting JSON can be directly loaded into databases, used in web APIs, or processed by data analysis tools.
If you need to generate Word documents from structured JSON data, see our tutorial on converting JSON to Word in Python, which covers creating Word content and tables directly from JSON objects and arrays.
5. Method 3 – Preserve Document Structure in JSON
Methods 1 and 2 treat paragraphs and tables as separate, isolated elements. In practice, Word documents have a meaningful hierarchy: headings introduce sections, paragraphs provide detail, and tables present structured data within a specific context.
Preserving this hierarchy in JSON produces output that is far more useful for knowledge base construction, RAG (Retrieval-Augmented Generation) pipelines, and document understanding systems. Instead of a flat list of text, you get a structured representation that maintains the logical flow of the original document.
How to Preserve Headings, Paragraphs, and Tables in a Hierarchical JSON Structure
The approach is to iterate through all child objects in each section's body, determine the type of each object (paragraph or table), and build a structured JSON representation accordingly. For paragraphs, you can detect headings by checking the StyleName property.
import json
from spire.doc import Document
from spire.doc.common import *
input_file = "ProjectReport.docx"
output_file = "structured_output.json"
HEADING_STYLES = {
"Heading1": 1,
"Heading2": 2,
"Heading3": 3,
"Heading4": 4,
}
def get_heading_level(style_name):
return HEADING_STYLES.get(style_name, None)
def extract_table_data(table):
rows_data = []
if table.Rows.Count < 1:
return {"headers": [], "rows": []}
header_row = table.Rows[0]
headers = []
for c in range(header_row.Cells.Count):
headers.append(header_row.Cells[c].Paragraphs[0].Text.strip())
for r in range(1, table.Rows.Count):
row = table.Rows[r]
row_dict = {}
for c in range(row.Cells.Count):
cell_text = row.Cells[c].Paragraphs[0].Text.strip()
row_dict[headers[c] if c < len(headers) else f"Column_{c}"] = cell_text
rows_data.append(row_dict)
return {"headers": headers, "rows": rows_data}
document = Document()
document.LoadFromFile(input_file)
sections_data = []
for i in range(document.Sections.Count):
section = document.Sections.get_Item(i)
content_items = []
for j in range(section.Body.ChildObjects.Count):
obj = section.Body.ChildObjects.get_Item(j)
if isinstance(obj, Paragraph):
text = obj.Text.strip()
if not text:
continue
heading_level = get_heading_level(obj.StyleName)
if heading_level:
content_items.append({
"type": "heading",
"level": heading_level,
"text": text
})
else:
content_items.append({
"type": "paragraph",
"text": text
})
elif isinstance(obj, Table):
table_data = extract_table_data(obj)
content_items.append({
"type": "table",
"row_count": len(table_data["rows"]),
"data": table_data
})
sections_data.append({
"section_index": i,
"content": content_items
})
document.Close()
result = {
"source": input_file,
"section_count": len(sections_data),
"sections": sections_data
}
with open(output_file, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
Output Example
The following JSON snippet shows how headings, paragraphs, and tables are represented in the hierarchical output structure:
{
"source": "ProjectReport.docx",
"section_count": 1,
"sections": [
{
"section_index": 0,
"content": [
{
"type": "heading",
"level": 1,
"text": "Quarterly Sales Report"
},
{
"type": "paragraph",
"text": "This report provides an overview of sales performance across all regions."
},
{
"type": "heading",
"level": 2,
"text": "Regional Breakdown"
},
{
"type": "table",
"row_count": 3,
"data": {
"headers": ["Region", "Product", "Units Sold", "Revenue"],
"rows": [
{"Region": "North", "Product": "Laptop", "Units Sold": "120", "Revenue": "114000"}
]
}
}
]
}
]
}
Conversion Result
The image below illustrates how headings, paragraphs, and tables are preserved in a hierarchical JSON structure.

Explanation
This method differs from the previous two in a fundamental way: it uses section.Body.ChildObjects to iterate through all content elements in document order, rather than separately iterating paragraphs and tables. This preserves the original sequence and interleaving of headings, paragraphs, and tables.
Key design decisions:
- Heading detection via
StyleName– Word headings are paragraphs styled with "Heading1", "Heading2", etc. Checking the style name allows you to distinguish headings from body text and record the heading level. Note that the exact heading style names may vary depending on the Word template or language settings (e.g., "Heading 1" with a space, or localized names like "标题 1" in Chinese). To handle these variations, normalize the style name before lookup:
def get_heading_level(style_name):
normalized = style_name.lower().replace(" ", "")
heading_map = {"heading1": 1, "heading2": 2, "heading3": 3, "heading4": 4}
return heading_map.get(normalized, None)
ChildObjectsiteration – Unlikesection.Paragraphs(which only returns paragraphs) orsection.Tables(which only returns tables),ChildObjectsreturns all elements in their original order. This is essential for preserving the document's logical structure.- Structured JSON output – Each content item includes a
typefield (heading,paragraph, ortable), making it easy for downstream systems to process different content types appropriately.
This approach is particularly valuable for:
- RAG and AI pipelines – the heading structure enables chunking documents by section, improving retrieval accuracy
- Knowledge base construction – hierarchical JSON maps directly to tree-structured knowledge graphs
- Document understanding – preserving the relationship between headings and their associated content allows semantic analysis of document sections
If you need to extract specific content types from Word documents, such as headings, paragraphs, or tables, see our tutorial on reading Word documents in Python, which covers content extraction techniques in more detail.
6. When to Use Word to JSON Conversion
Word to JSON conversion is useful in any scenario where structured data needs to be extracted from Word documents at scale. Common use cases include:
- AI and RAG document processing – Convert Word documents into JSON chunks for embedding and retrieval in LLM-based applications. The hierarchical structure from Method 3 enables section-level chunking, which produces better retrieval results than flat text splitting.
- Knowledge base construction – Build structured knowledge bases from technical documentation, policy documents, or manuals stored as .docx files.
- Batch data extraction – Extract data from hundreds of Word reports, invoices, or forms and load the results into a database or data warehouse.
- Contract and resume parsing – Convert legal contracts, HR documents, or resumes into structured JSON for automated analysis and comparison.
- API and web application data exchange – Serve Word document content through REST APIs as JSON, enabling web and mobile applications to consume document data without handling .docx files directly.
7. Limitations and Best Practices
Limitations
- No standard JSON schema for Word – Unlike CSV or XML, there is no universally accepted format for representing Word content in JSON. The structure you choose must be designed for your specific use case.
- Complex formatting is not captured – The methods in this tutorial extract text content and basic structural metadata (heading levels, table data). They do not capture fonts, colors, images, page layout, headers/footers, or footnotes. If your application requires these elements, additional extraction logic is needed.
- Merged table cells require special handling – Word tables can contain merged cells (both horizontal and vertical). The simple row-by-row extraction in Method 2 assumes a regular grid. Documents with merged cells may produce unexpected results.
- Large documents may need chunked processing – For documents with hundreds of pages or dozens of tables, consider processing sections or tables individually to manage memory usage.
Best Practices
- Design your JSON schema before writing code – Decide what you need (text only? headings? tables? full structure?) and choose the appropriate extraction method.
- Validate output against sample documents – Word documents vary widely in structure and formatting. Test your conversion logic against representative samples from your actual document set.
- Handle encoding explicitly – Always specify
encoding="utf-8"when writing JSON files to avoid character encoding issues with non-ASCII text. - Use
ensure_ascii=Falseinjson.dump– This preserves Unicode characters in the output rather than escaping them, which is important for documents containing non-English text.
8. FAQ
Can I convert DOCX to JSON in Python?
Yes. Using Spire.Doc for Python, you can load any .docx file, iterate through its sections, paragraphs, and tables, and serialize the extracted content to JSON using Python's built-in json module. This tutorial demonstrates three methods for doing so, from simple text extraction to full structural preservation.
What is the best Word to JSON converter for developers?
For developers who need batch processing, automation, or custom JSON schemas, a Python-based approach using Spire.Doc is more flexible than online converters. Online tools work for one-off conversions but cannot handle large-scale processing, custom output formats, or integration into automated pipelines.
Can I convert Word tables to JSON?
Yes. By iterating through the tables in a Word document and extracting cell text row by row, you can convert table data into a JSON array of objects. Method 2 in this tutorial demonstrates this with header-based key mapping.
Does Word have a native JSON export option?
No. Microsoft Word does not provide a built-in JSON export format. Word files can be saved as DOCX, PDF, HTML, RTF, and plain text, but converting to JSON requires a programmatic approach that reads the document structure and maps it to a JSON schema.
Can I preserve headings and structure when converting Word to JSON?
Yes. By iterating through all child objects in each section's body and checking paragraph style names, you can detect headings, body paragraphs, and tables, then build a hierarchical JSON structure that preserves the document's logical organization. Method 3 in this tutorial provides a complete implementation.
Can I convert Word to JSON online?
Yes, there are online Word to JSON converters that can handle one-off conversions. However, online tools are limited to single-file processing and do not allow customization of the JSON schema. For batch processing, automated pipelines, or custom output structures, a Python-based approach using Spire.Doc is more practical and scalable.
9. Conclusion
In this article, we demonstrated how to convert Word documents to JSON in Python using Spire.Doc for Python. We covered three methods of increasing complexity: extracting paragraph text as a flat JSON array, converting Word tables to structured JSON objects, and preserving the full document hierarchy—including headings, paragraphs, and tables—in a single JSON output.
Each method serves a different purpose. Plain text extraction works for indexing and embedding. Table extraction is ideal for data migration and report parsing. Full structural preservation enables knowledge base construction and RAG pipelines. Choose the approach that matches your requirements, and extend the JSON schema as needed for your specific use case.
Spire.Doc for Python provides comprehensive Word document processing capabilities beyond JSON conversion, including document creation, formatting, mail merge, and format conversion. You can apply for a 30-day free license to evaluate all features.
How to Convert JSON to Word in Python (JSON to DOCX)

JSON is one of the most common formats for exchanging structured data between applications, APIs, and databases. In many business scenarios, however, JSON data needs to be transformed into human-readable Word documents such as reports, invoices, summaries, contracts, or exported records.
Converting JSON to Word is not a simple file format conversion. JSON has no inherent Word structure, so the process requires parsing the JSON data and mapping its elements to appropriate Word document components such as paragraphs, tables, and headings.
This article demonstrates how to convert JSON data into Word documents in Python using Spire.Doc for Python. We'll cover multiple approaches, including exporting JSON as formatted text, creating Word tables from JSON arrays, and generating structured reports from nested JSON data.
Content Overview
- Understanding JSON-to-Word Conversion
- Install Spire.Doc for Python
- Method 1: Convert JSON to Word as Formatted Text
- Method 2: Convert JSON Arrays to Word Tables
- Method 3: Generate Structured Word Reports from JSON
- Handle Nested JSON Objects
- Handle Missing or Optional Fields
- Convert JSON Files to Word Documents
- Why Use Spire.Doc for JSON-to-Word Conversion
- FAQ
- Conclusion
1. Understanding JSON-to-Word Conversion
JSON and Word documents serve fundamentally different purposes. JSON is a structured data format designed for data exchange and machine processing, while Word documents are intended for human consumption with rich formatting, visual hierarchy, and page layout.
As a result, converting JSON to Word is not a direct format transformation. The JSON data must first be parsed and mapped to appropriate document elements before a Word document can be generated.
The conversion process typically follows this workflow:
JSON Data
↓
Parse JSON (json.loads)
↓
Map Data Structure
↓
Spire.Doc for Python
↓
Paragraphs / Tables / Headings
↓
DOCX Document
In Python, the built-in json module is commonly used to parse JSON data, while Spire.Doc for Python handles document generation. After the JSON structure is analyzed and mapped, Spire.Doc can create paragraphs, tables, headings, images, and other Word elements programmatically, producing a fully formatted DOCX document.
The table below shows common mappings between JSON structures and Word elements:
| JSON Structure | Word Element | Example |
|---|---|---|
| Key-Value Pair | Paragraph | "Name": "John" → Name: John |
| Array | Table | [{...}, {...}] → rows and columns |
| Object | Section | Nested object → grouped content |
| Title Field | Heading | "title": "Report" → Heading 1 |
| URL/Image Path | Image | "logo": "img.png" → embedded image |
Understanding these mappings is important because the same JSON data can be presented in different ways depending on the document's purpose. For example, simple key-value data may be exported as paragraphs, while collections of records are usually easier to read when rendered as tables. With Spire.Doc for Python, these mappings can be implemented programmatically to generate professional Word documents from structured JSON data.
2. Install Spire.Doc for Python
Before converting JSON to Word, you need to install Spire.Doc for Python in your development environment.
Install via pip (Recommended)
pip install spire.doc
Alternatively, you can download Spire.Doc for Python and integrate it manually.
After installation, import the library in your project:
from spire.doc import *
from spire.doc.common import *
3. Method 1: Convert JSON to Word as Formatted Text
This method is the simplest approach for converting JSON to Word. It works well for API responses, configuration files, and simple JSON exports where each key-value pair maps to a paragraph.
Sample JSON
{
"Name": "John Smith",
"Department": "Sales",
"Country": "USA"
}
Python Code
import json
from spire.doc import Document, FileFormat, HorizontalAlignment
json_data = '{"Name": "John Smith", "Department": "Sales", "Country": "USA"}'
data = json.loads(json_data)
document = Document()
section = document.AddSection()
for key, value in data.items():
paragraph = section.AddParagraph()
text_range = paragraph.AppendText(f"{key}: {value}")
text_range.CharacterFormat.FontSize = 12
paragraph.Format.AfterSpacing = 6
document.SaveToFile("json_to_text.docx", FileFormat.Docx)
document.Close()
Output
The following Word document shows how JSON key-value pairs can be converted into formatted paragraphs.

When to Use This Approach
This method is best suited for:
- Simple key-value JSON objects
- API response exports
- Configuration file documentation
- Quick data snapshots
It is not ideal for large datasets or tabular data, where Method 2 (tables) provides better readability.
If your goal is to analyze, filter, or manipulate structured JSON data in a spreadsheet, you may also be interested in our guide on converting JSON to Excel in Python.
4. Method 2: Convert JSON Arrays to Word Tables
When JSON data contains arrays of objects, tables provide the most effective way to present the data in a Word document. This is the most common scenario for converting JSON to Word, as many APIs and databases return data as JSON arrays.
Sample JSON
[
{"Product": "Laptop", "Price": 1200, "Stock": 45},
{"Product": "Mouse", "Price": 30, "Stock": 200},
{"Product": "Keyboard", "Price": 85, "Stock": 120}
]
Python Code
import json
from spire.doc import (
Document, FileFormat, HorizontalAlignment,
VerticalAlignment, TableRowHeightType, Color
)
json_data = '''[
{"Product": "Laptop", "Price": 1200, "Stock": 45},
{"Product": "Mouse", "Price": 30, "Stock": 200},
{"Product": "Keyboard", "Price": 85, "Stock": 120}
]'''
data = json.loads(json_data)
document = Document()
section = document.AddSection()
if data:
headers = list(data[0].keys())
table = section.AddTable(True)
table.ResetCells(len(data) + 1, len(headers))
header_row = table.Rows[0]
header_row.IsHeader = True
header_row.Height = 20
header_row.HeightType = TableRowHeightType.Exactly
for col_index, header in enumerate(headers):
header_row.Cells[col_index].CellFormat.Shading.BackgroundPatternColor = Color.get_Gray()
header_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = header_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
text_range = paragraph.AppendText(header)
text_range.CharacterFormat.Bold = True
text_range.CharacterFormat.FontSize = 12
for row_index, record in enumerate(data):
data_row = table.Rows[row_index + 1]
data_row.Height = 20
data_row.HeightType = TableRowHeightType.Exactly
for col_index, key in enumerate(headers):
data_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = data_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
text_range = paragraph.AppendText(str(record.get(key, "")))
text_range.CharacterFormat.FontSize = 11
document.SaveToFile("json_to_table.docx", FileFormat.Docx)
document.Close()
Output
The following screenshot shows the generated Word table created from the JSON array.

Why Use Tables for JSON Arrays
Tables are the natural fit for JSON array data because:
- Each JSON object maps to a table row
- Each key maps to a column header
- Data is aligned for easy scanning and comparison
- Tables are the standard format for reports, inventory lists, and exported database records
Enhancing JSON Tables with Formatting
Unlike plain text exports, Spire.Doc allows JSON data to be rendered as professionally formatted Word tables. Beyond basic table creation, you can apply:
- Table styles – Use
DefaultTableStyleorApplyStylefor consistent, polished table appearances - Borders and shading – Control cell borders, background colors, and alternating row colors
- Alignment – Set horizontal and vertical alignment at the cell, row, or table level
- Custom formatting – Apply font size, bold, and color to individual cells or ranges
- Auto-fit behavior – Use
AutoFitto adjust column widths to content or window size
These formatting capabilities transform raw JSON data into professional report layouts suitable for business documents, client deliverables, and automated reporting pipelines.
If you need to create more sophisticated Word tables, such as merged cells, custom table layouts, or advanced formatting, see our guide on creating and formatting tables in Word documents using Python.
5. Method 3: Generate Structured Word Reports from JSON
Real-world JSON data often contains a mix of metadata, summary text, and tabular data. This method combines headings, paragraphs, and tables to generate a complete structured Word report from JSON.
Sample JSON
{
"title": "Monthly Sales Report",
"period": "June 2026",
"summary": "Total revenue reached $580,000 this month, representing a 12% increase over the previous period. All regions showed positive growth.",
"sales": [
{"Region": "North", "Revenue": 150000, "Units": 320},
{"Region": "South", "Revenue": 120000, "Units": 280},
{"Region": "East", "Revenue": 180000, "Units": 410},
{"Region": "West", "Revenue": 130000, "Units": 290}
]
}
Python Code
import json
from spire.doc import (
Document, FileFormat, HorizontalAlignment,
VerticalAlignment, TableRowHeightType, Color,
BuiltinStyle
)
json_data = '''{
"title": "Monthly Sales Report",
"period": "June 2026",
"summary": "Total revenue reached $580,000 this month, representing a 12% increase over the previous period. All regions showed positive growth.",
"sales": [
{"Region": "North", "Revenue": 150000, "Units": 320},
{"Region": "South", "Revenue": 120000, "Units": 280},
{"Region": "East", "Revenue": 180000, "Units": 410},
{"Region": "West", "Revenue": 130000, "Units": 290}
]
}'''
data = json.loads(json_data)
document = Document()
section = document.AddSection()
heading_style = document.AddStyle(BuiltinStyle.Heading1)
subheading_style = document.AddStyle(BuiltinStyle.Heading2)
title_para = section.AddParagraph()
title_para.ApplyStyle(heading_style.Name)
title_para.AppendText(data.get("title", "Report"))
period_para = section.AddParagraph()
period_para.AppendText(f"Period: {data.get('period', 'N/A')}")
period_para.Format.AfterSpacing = 12
summary_heading = section.AddParagraph()
summary_heading.ApplyStyle(subheading_style.Name)
summary_heading.AppendText("Executive Summary")
summary_para = section.AddParagraph()
summary_para.AppendText(data.get("summary", ""))
summary_para.Format.AfterSpacing = 12
sales_heading = section.AddParagraph()
sales_heading.ApplyStyle(subheading_style.Name)
sales_heading.AppendText("Sales Data")
sales = data.get("sales", [])
if sales:
headers = list(sales[0].keys())
table = section.AddTable(True)
table.ResetCells(len(sales) + 1, len(headers))
header_row = table.Rows[0]
header_row.IsHeader = True
header_row.Height = 20
header_row.HeightType = TableRowHeightType.Exactly
for col_index, header in enumerate(headers):
header_row.Cells[col_index].CellFormat.Shading.BackgroundPatternColor = Color.get_Gray()
header_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = header_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
text_range = paragraph.AppendText(header)
text_range.CharacterFormat.Bold = True
for row_index, record in enumerate(sales):
data_row = table.Rows[row_index + 1]
data_row.Height = 20
data_row.HeightType = TableRowHeightType.Exactly
for col_index, key in enumerate(headers):
data_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = data_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
paragraph.AppendText(str(record.get(key, "")))
document.SaveToFile("json_report.docx", FileFormat.Docx)
document.Close()
Output
The generated Word document combines headings, descriptive text, and tabular data into a structured report, making the JSON data easier to read and share.

Key Techniques
This example demonstrates several important techniques for generating Word reports from JSON:
- Headings – Use
BuiltinStyle.Heading1andHeading2for document structure and table-of-contents compatibility - Paragraphs – Add summary and descriptive text between headings
- Tables – Render JSON arrays as tabular data within the report
- Combinations – Mix multiple Word element types in a single document
Why Structured Reports Matter
In business environments, JSON data rarely exists in isolation. It typically comes from APIs, databases, or reporting systems and needs to be transformed into documents that decision-makers can read, share, and archive. Common scenarios include:
- Sales reports – Revenue, units, and regional breakdowns from CRM or ERP systems
- Inventory reports – Stock levels, reorder alerts, and warehouse summaries
- Customer summaries – Contact details, order history, and account status
- Compliance reports – Audit logs, access records, and policy status
- Automated reporting systems – Scheduled jobs that generate documents from JSON data and distribute them via email or document management systems
Spire.Doc makes it possible to transform structured JSON data into polished business documents automatically, combining headings, paragraphs, and tables in a single output.
If you need to build more sophisticated document layouts, such as multi-section reports, cover pages, tables of contents, headers, footers, or custom document templates, see our guide on creating structured Word documents in Python.
6. Handle Nested JSON Objects
Many real-world JSON responses contain nested objects. For example, a customer record may include an address object with its own fields. Handling these nested structures is essential for complete JSON-to-Word conversion.
Example JSON
{
"customer": {
"name": "Tom Wilson",
"email": "tom@example.com",
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL"
}
}
}
Python Code
import json
from spire.doc import Document, FileFormat, HorizontalAlignment
def add_nested_object(section, obj, indent_level=0):
for key, value in obj.items():
if isinstance(value, dict):
heading_para = section.AddParagraph()
heading_text = " " * indent_level + key.capitalize()
text_range = heading_para.AppendText(heading_text)
text_range.CharacterFormat.Bold = True
text_range.CharacterFormat.FontSize = 12 - indent_level
heading_para.Format.AfterSpacing = 4
add_nested_object(section, value, indent_level + 1)
else:
paragraph = section.AddParagraph()
label = " " * indent_level + f"{key}: {value}"
text_range = paragraph.AppendText(label)
text_range.CharacterFormat.FontSize = 11
paragraph.Format.AfterSpacing = 2
json_data = '''{
"customer": {
"name": "Tom Wilson",
"email": "tom@example.com",
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL"
}
}
}'''
data = json.loads(json_data)
document = Document()
section = document.AddSection()
add_nested_object(section, data)
document.SaveToFile("json_nested.docx", FileFormat.Docx)
document.Close()
Output
The following screenshot shows the hierarchical Word document generated from the nested JSON structure.

Nested JSON objects can be represented as hierarchical sections in a Word document, making complex data structures easier to read and navigate.
How It Works
The add_nested_object function recursively traverses the JSON structure:
- When it encounters a dict value, it creates a bold heading for the key and recurses into the nested object
- When it encounters a scalar value, it creates a paragraph with the key-value pair
- The
indent_levelparameter controls indentation and font size to create a visual hierarchy
This recursive approach handles arbitrarily deep nesting and produces a readable hierarchical layout in the Word document.
7. Handle Missing or Optional JSON Fields
In real-world applications, JSON data from APIs and databases often contains missing or optional fields. Records may have inconsistent keys, and some fields may be absent entirely. Handling these cases gracefully prevents errors and ensures the generated Word document remains complete.
Example JSON with Missing Fields
[
{"Name": "Tom Wilson", "Email": "tom@example.com", "Phone": "555-0100"},
{"Name": "Jane Doe", "Email": "jane@example.com"},
{"Name": "Bob Brown", "Phone": "555-0300"}
]
Python Code
import json
from spire.doc import (
Document, FileFormat, HorizontalAlignment,
VerticalAlignment, TableRowHeightType, Color
)
json_data = '''[
{"Name": "Tom Wilson", "Email": "tom@example.com", "Phone": "555-0100"},
{"Name": "Jane Doe", "Email": "jane@example.com"},
{"Name": "Bob Brown", "Phone": "555-0300"}
]'''
data = json.loads(json_data)
document = Document()
section = document.AddSection()
if data:
all_keys = []
for record in data:
for key in record.keys():
if key not in all_keys:
all_keys.append(key)
table = section.AddTable(True)
table.ResetCells(len(data) + 1, len(all_keys))
header_row = table.Rows[0]
header_row.IsHeader = True
header_row.Height = 20
header_row.HeightType = TableRowHeightType.Exactly
for col_index, header in enumerate(all_keys):
header_row.Cells[col_index].CellFormat.Shading.BackgroundPatternColor = Color.get_Gray()
header_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = header_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
text_range = paragraph.AppendText(header)
text_range.CharacterFormat.Bold = True
for row_index, record in enumerate(data):
data_row = table.Rows[row_index + 1]
data_row.Height = 20
data_row.HeightType = TableRowHeightType.Exactly
for col_index, key in enumerate(all_keys):
data_row.Cells[col_index].CellFormat.VerticalAlignment = VerticalAlignment.Middle
paragraph = data_row.Cells[col_index].AddParagraph()
paragraph.Format.HorizontalAlignment = HorizontalAlignment.Center
paragraph.AppendText(str(record.get(key, "N/A")))
document.SaveToFile("json_missing_fields.docx", FileFormat.Docx)
document.Close()
Output
The following screenshot shows the generated Word table, where missing fields are automatically filled with placeholder values to maintain a consistent document structure.

Key Techniques
dict.get(key, "N/A")– Returns a default value when a key is missing, preventingKeyErrorexceptions- Dynamic column collection – Iterates all records to build a complete set of column headers, ensuring no field is missed even when it appears in only some records
- Consistent table structure – All rows have the same number of columns regardless of which fields are present in each record
This approach is essential for production use cases where API responses may vary in structure across different records or over time.
8. Convert JSON Files to Word Documents
In practice, JSON data often originates from files rather than inline strings. API export results, configuration files, database dumps, data exchange files, and log data are all commonly stored as .json files that need to be converted to Word documents.
The conversion process for JSON files follows this workflow:
JSON File (.json)
↓
Load JSON (json.load)
↓
Generate Word Document (Spire.Doc)
↓
DOCX Document
Python Code
import json
from spire.doc import Document, FileFormat
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
document = Document()
section = document.AddSection()
# Process the loaded JSON data
# using any of the techniques shown in Methods 1–3
# (formatted text, tables, or structured reports)
document.SaveToFile("data_report.docx", FileFormat.Docx)
document.Close()
Key Points
json.load()reads and parses a JSON file directly, unlikejson.loads()which parses a stringencoding="utf-8"ensures proper handling of non-ASCII characters in JSON files- Once the JSON file is loaded into a Python dictionary or list, Spire.Doc for Python can generate paragraphs, tables, or structured reports from the parsed data using any of the methods described earlier in this article
For complete examples of processing the loaded data, refer to Method 1 for formatted text, Method 2 for tables, or Method 3 for structured reports.
9. Why Use Spire.Doc for JSON-to-Word Conversion
Converting JSON to Word involves several practical challenges that go beyond simple data parsing. Generating properly formatted tables, applying consistent styles, creating structured reports with headings and paragraphs, and handling nested or incomplete data all require a capable document generation API.
Challenges of JSON-to-Word Conversion
- Table generation – JSON arrays must be mapped to Word tables with headers, rows, and cell formatting
- Document formatting – Raw data exports lack the visual hierarchy that makes Word documents readable
- Structured reports – Combining headings, paragraphs, and tables in a single document requires coordinating multiple element types
- Nested data – Deeply nested JSON objects need recursive traversal and hierarchical layout
- Large documents – Generating multi-page reports from large JSON datasets demands efficient resource management
Benefits of Spire.Doc for Python
Spire.Doc for Python addresses these challenges with a straightforward API:
- Create Word documents without Microsoft Word – No Office installation or Interop dependencies required
- Generate paragraphs, tables, images, headers, and footers – Full coverage of Word document elements
- Apply built-in and custom styles – Consistent formatting across documents using
BuiltinStyleandParagraphStyle - Automate report generation – Programmatically build structured reports from any JSON data source
- Export to DOCX and other formats – Save to DOCX, PDF, HTML, RTF, and more using
FileFormat
With Spire.Doc, the JSON-to-Word conversion process becomes a structured mapping from parsed data to Word elements, rather than manual string formatting or template manipulation.
10. FAQ
How do I convert JSON to Word in Python?
Parse the JSON data using Python's built-in json module, then use Spire.Doc for Python to create a Word document. Map JSON key-value pairs to paragraphs, JSON arrays to tables, and use headings for structure. See Method 1 for a basic example and Method 3 for a complete report.
Can JSON arrays be converted into Word tables?
Yes. JSON arrays of objects map naturally to Word tables, where each object becomes a row and each key becomes a column. See Method 2 for a complete code example that creates a formatted table from a JSON array.
How do I create a DOCX report from API JSON responses?
Fetch the API response as JSON, parse it, and use Spire.Doc for Python to generate the report. Combine headings for titles, paragraphs for summaries, and tables for data arrays. See Method 3 for a structured report example.
Can nested JSON objects be exported to Word?
Yes. Use a recursive function to traverse nested JSON objects, creating headings for object keys and paragraphs for scalar values. See Section 6 for a detailed example of handling nested structures with visual hierarchy.
How do I convert a JSON file to a Word document?
Use Python's json.load() to read the JSON file, then process the parsed data with Spire.Doc for Python. See Section 8 for a code example.
What is the best way to generate Word documents from JSON data?
The best approach depends on the JSON structure. For simple key-value data, use formatted paragraphs. For arrays, use tables. For complex nested data with mixed content, combine headings, paragraphs, and tables as shown in Method 3.
11. Conclusion
Generating Word documents from JSON data is a common requirement in reporting, document automation, and data export workflows. With Spire.Doc for Python, you can create paragraphs, tables, and structured document layouts directly from JSON, making it easier to produce professional DOCX files from application data.
The same approach can be extended to API responses, database records, configuration files, and other structured data sources, helping automate document generation in both small projects and enterprise systems.
For scenarios involving large documents or document conversion requirements, a licensed version is required.