Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 201 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# OpenXMLSDK.Engine

This library let you to create quickly some docx documents, based on the ooxml sdk of Microsoft.

By using the WordManager object, you will be able to geneate quickly your documents.
A .NET library that simplifies generating and manipulating Word (.docx) documents using the OpenXML SDK. Use the `WordManager` object and the built-in Report Engine to produce rich documents from templates or from scratch.


## Quality and packaging
Expand All @@ -12,46 +10,219 @@ By using the WordManager object, you will be able to geneate quickly your docume
[![NuGet package](https://buildstats.info/nuget/OpenXMLSDK.Engine?includePreReleases=true)](https://nuget.org/packages/OpenXMLSDK.Engine)


### API
## API

The API of `WordManager` is designed to be easy to understand and use.

### Open an existing template

Call `OpenDocFromTemplate` to open a `.dotx` template, copy it to a new path and work on the copy:

```csharp
var templatePath = @"C:\temp\template.dotx";
var outputPath = @"C:\temp\createdDoc.docx";

using (var word = new WordManager())
{
word.OpenDocFromTemplate(templatePath, outputPath, isEditable: true);

// ... make changes ...

word.SaveDoc();
word.CloseDoc();
}
```

You can also open a template from a `Stream` (useful in web or cloud scenarios):

```csharp
using (var templateStream = File.OpenRead(@"C:\temp\template.dotx"))
using (var word = new WordManager())
{
word.OpenDocFromTemplate(templateStream);

// ... make changes ...

word.SaveDoc();
var result = word.GetMemoryStream(); // returns a copy of the document as a MemoryStream
}
```

### Insert text on a bookmark

The API of WordManager is very easy to understand and to use.
Templates can contain named bookmarks. Use the bookmark extension methods to inject content:

#### WordManager Open existing template
```csharp
using (var word = new WordManager())
{
word.OpenDocFromTemplate(templatePath, outputPath, isEditable: true);

In order to open a template, call the OpenDocFromTemplate method
```c#

var resourceName = "<Set full template file path here>"; // ex : C:\temp\template.dotx
var finalFilePath = "<Set saved new document file path here>"; // ex : C:\temp\createdDoc.docx

using (var word = new WordManager())
// Insert a plain string at a bookmark named "CompanyName"
word.SetTextOnBookmark("CompanyName", "Contoso Ltd.");

// Insert multiple lines at a bookmark named "AddressLines"
word.SetTextsOnBookmark("AddressLines", new List<string>
{
word.OpenDocFromTemplate(resourceName, finalFilePath, true);
"1 Microsoft Way",
"Redmond, WA 98052"
});

word.SaveDoc();
word.CloseDoc();
}

// Replace a bookmark with HTML content
word.SetHtmlOnBookmark("BodyContent", "<p>Hello <strong>World</strong></p>");

word.SaveDoc();
word.CloseDoc();
}
```

#### WordManager Insert text on bookmark
### Report Engine – generate a document from a model

The Report Engine lets you define an entire document as a C# object tree, bind it to a `ContextModel` and render it to bytes in one call.

#### Build a simple document

Using the name of the database and the folder on the client device where to store database files:
```c#

var resourceName = "<Set full template file path here>"; // ex : C:\temp\template.dotx
var finalFilePath = "<Set saved new document file path here>"; // ex : C:\temp\createdDoc.docx

using (var word = new WordManager())
```csharp
using OpenXMLSDK.Engine.Word;
using OpenXMLSDK.Engine.Word.ReportEngine;
using OpenXMLSDK.Engine.Word.ReportEngine.Models;
using OpenXMLSDK.Engine.ReportEngine.DataContext;
using OpenXMLSDK.Engine.ReportEngine.DataContext.FluentExtensions;
using System.Globalization;

// 1. Build the document model
var document = new Document();
var page = new Page();
document.Pages.Add(page);

var paragraph = new Paragraph();
page.ChildElements.Add(paragraph);

paragraph.ChildElements.Add(new Label { Text = "Hello, #CustomerName#!" });

// 2. Build the context (data bindings)
var context = new ContextModel()
.AddString("#CustomerName#", "Alice");

// 3. Generate bytes
using var word = new WordManager();
byte[] docBytes = word.GenerateReport(document, context, CultureInfo.InvariantCulture);
File.WriteAllBytes(@"C:\temp\output.docx", docBytes);
```

#### Render a table from a collection

```csharp
var document = new Document();
var page = new Page();
document.Pages.Add(page);

var table = new Table
{
DataSourceKey = "#Orders#",
ColsWidth = new[] { 3000, 3000, 2000 },
HeaderRow = new Row
{
Cells =
{
new Cell { ChildElements = { new Label { Text = "Product", Bold = true } } },
new Cell { ChildElements = { new Label { Text = "Quantity", Bold = true } } },
new Cell { ChildElements = { new Label { Text = "Price", Bold = true } } },
}
},
RowModel = new Row
{
word.OpenDocFromTemplate(resourceName, finalFilePath, true);
Cells =
{
new Cell { ChildElements = { new Label { Text = "#Product#" } } },
new Cell { ChildElements = { new Label { Text = "#Quantity#" } } },
new Cell { ChildElements = { new Label { Text = "#Price#" } } },
}
}
};
page.ChildElements.Add(table);

// Build a data-source collection
var context = new ContextModel()
.AddCollection("#Orders#",
new ContextModel().AddString("#Product#", "Widget A").AddString("#Quantity#", "10").AddString("#Price#", "$5.00"),
new ContextModel().AddString("#Product#", "Widget B").AddString("#Quantity#", "3").AddString("#Price#", "$15.00")
);

using var word = new WordManager();
byte[] docBytes = word.GenerateReport(document, context, CultureInfo.InvariantCulture);
```

#### Multi-report generation (multiple sections)

word.SaveDoc();
word.CloseDoc();
```csharp
var reports = new List<Report>
{
new Report
{
Document = BuildCoverPageDocument(),
ContextModel = BuildCoverPageContext(),
AddPageBreak = true
},
new Report
{
Document = BuildContentDocument(),
ContextModel = BuildContentContext(),
AddPageBreak = false
}

};

using var word = new WordManager();
byte[] docBytes = word.GenerateReport(reports, mergeStyles: true, CultureInfo.CurrentCulture);
```

### Append an external document

Append one or more Word documents at the end of the current document:

```csharp
using (var word = new WordManager())
{
word.OpenDocFromTemplate(templatePath, outputPath, isEditable: true);

using var extra = File.OpenRead(@"C:\temp\annex.docx");
word.AppendSubDocument(extra, withPageBreak: true);

word.SaveDoc();
word.CloseDoc();
}
```

### Create a new blank document

```csharp
using (var word = new WordManager())
{
word.New();

// ... add content programmatically ...

word.SaveDoc();
var stream = word.GetMemoryStream();
}
```

### Context fluent extensions reference

`ContextModel` supports a fluent API for adding typed values:

| Method | Description |
|---|---|
| `AddString(key, value)` | Plain string |
| `AddDouble(key, value, pattern)` | Formatted double (e.g. `"{0:N2}"`) |
| `AddBoolean(key, value)` | Boolean (controls `Show`, `Bold`, etc.) |
| `AddDateTime(key, value, pattern)` | Formatted date/time |
| `AddByteContent(key, bytes)` | Inline image from a byte array |
| `AddBase64Content(key, base64)` | Inline image from a Base64 string |
| `AddFileLink(key, filePath)` | File reference (image path or any file path used by the report engine) |
| `AddSubstitutableString(key, pattern, dataSource)` | Composite string, e.g. `"{0} of {1}"` |
| `AddCollection(key, contexts...)` | Data source for `ForEach` or table row models |


# Contribute

## How to contribute
Expand Down
2 changes: 1 addition & 1 deletion src/OpenXMLSDK.Engine/OpenXMLSDK.Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageProjectUrl>https://github.com/mathieumack/OpenXMLSDK.Engine</PackageProjectUrl>
<RepositoryUrl>https://github.com/mathieumack/OpenXMLSDK.Engine</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Description>This package contains the 'Open-XML-SDK' plugin for MvvmCross.</Description>
<Description>A .NET library that simplifies generating and manipulating Word (.docx) documents using the OpenXML SDK. Provides a high-level report engine, bookmark utilities, chart support, and fluent extension methods for building documents from templates or from scratch.</Description>
<RootNamespace>OpenXMLSDK.Engine</RootNamespace>
<AssemblyName>OpenXMLSDK.Engine</AssemblyName>
<Product>engine report and helpers for the OpenXML SDK</Product>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,35 @@ public static ContextModel AddBase64Content(this ContextModel context, string ke
return context;
}

/// <summary>
/// Add a file link model (image path or any file reference used by the report engine)
/// </summary>
/// <param name="context"></param>
/// <param name="key"></param>
/// <param name="filePath">Absolute or relative path to the file</param>
/// <returns></returns>
public static ContextModel AddFileLink(this ContextModel context, string key, string filePath)
{
var element = new FileLinkModel(filePath);
context.AddItem(key, element);
return context;
}

/// <summary>
/// Add a substitutable string model, allowing composite formatted strings built from other context values
/// </summary>
/// <param name="context"></param>
/// <param name="key"></param>
/// <param name="renderPattern">Format pattern (e.g. "{0} of {1}")</param>
/// <param name="dataSource">Context whose values are injected into the pattern in order</param>
/// <returns></returns>
public static ContextModel AddSubstitutableString(this ContextModel context, string key, string renderPattern, ContextModel dataSource)
{
var element = new SubstitutableStringModel(renderPattern, dataSource);
context.AddItem(key, element);
return context;
}

/// <summary>
/// Add a list of elements as a DataSource
/// </summary>
Expand Down
Loading