SkillAgentSearch skills...

DXPlus

.NET Core library to edit and manipulate the OpenXML .docx format.

Install / Use

/learn @markjulmar/DXPlus
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

DXPlus - DocX parser and formatter library

This library is a fork of DocX which has been heavily modified in a variety of ways, including adding support for later versions of Word. The library allows you to load or create Word documents and edit them with .NET Core code. No Office interop libraries are used and the source is fully managed code.

Build and Publish DXPlus library

The library is available on NuGet:

Install-Package Julmar.DxPlus -Version 1.4.0-preview

Note:

The original DocX code has been purchased by Xceed and is now maintained in their open source GitHub repo with options for support.

Dependencies

This is currently built against .NET 8 and uses SixLabors.Fonts to retrieve the font families, and SkiaSharp to work with images in the documents.

Working with documents

Word documents are primarily composed of sections, paragraphs and tables. There is always at least one section in every document which contains the main body. Other sections can be added to change page-level characteristics such as orientation or margins. In addition, headers and footers are held in their own sections.

Within a section the document has paragraphs and tables. Paragraphs have properties, which control formatting and visual characteristics, and runs of text or drawings (images, videos, etc.) which provide the content. A run also has properties which provide fine-tuning for colors or fonts or even override the paragraph-level formatting. Here's a basic structure:

Document
  |               +-- Headers --- Paragraph(s)
  |               |
  +--- Section ---+-- Properties
          |       |
          |       +-- Footers --- Paragraph(s)
          |
          +--- Paragraph                 
          +--- Paragraph    
          +--- Paragraph --- Properties
                   |
                   +--- Run
                   +--- Run
                   +--- Run --- Properties
                         |
                         +--- Text / Drawing
                         +--- Text / Drawing
                         +--- Text / Drawing

Create a new document

The library is oriented around the IDocument interface. It provides the basis for working with a single document. The primary namespace is DXPlus, and there's a secondary namespace for all the charting capabilities (DXPlus.Charts). Here is a synthesis of all the capabilities at the document level - this combines the interface along with all extension methods.

Documents are created and opened with the static Document class. You can open or create documents with static methods on this class.

public class Document
{
    public static IDocument Load(string filename);
    public static IDocument Load(Stream stream);
    public static IDocument Create(string filename = null);
    public static IDocument CreateTemplate(string filename = null);
}

It has Create and Open methods which return the IDocument interface.

IDocument document = Document.Create("test.docx"); // named -- but not written until Save is called.

...

document = Document.Create(); // No name -- must use SaveAs

Open a document

You can open a document from a file or a stream (including a network stream).

// Can read from an existing local document.
IDocument document = Document.Open("test.docx")

...

// Can read from a stream.
var document = Document.Open(await client.ReadAsStreamAsync())

Saving and closing documents

The IDocument interface implements IDisposable. Disposing the document is the same as closing it - it will release all the open resources. If you make changes to the document you need to call Save or SaveAs to commit those changes to the file or stream.

If Save is used, then the document must have a filename associated with it or an exception will be thrown.

IDocument document = Document.Open("test.docx")
 ....

document.Save();
document.Close();
using var document = Document.Create(); // can also pass a filename into Create
 ...
document.SaveAs("test.docx");

Fluent API

Most of the API is fluent in nature so each method returns the called object. This allows you to 'string together' changes to a paragraph, block, or section. Many of these methods are extension methods in the DXPlus namespace added to the Paragraph, Document, Table and Picture classes. Here's an example usage which creates a paragraph with an embedded hyperlink.

var paragraph = new Paragraph()
    .AddText("This line contains a ")
    .Add(new Hyperlink("link", new Uri("http://www.microsoft.com")))
    .AddText(".");

// Add the paragraph to the document
doc.Add(paragraph);

Add paragraphs

The most common action is to add paragraphs of text. This is done with the Add method. You can add additional text to the paragraph with the AddText method. A second parameter allows you to specify formatting such as text color, font, bold, etc. You can terminate a line with a carriage return with the Newline method. Here's an example:

var document = Document.Create();
var p = document.Add("Hello, World! This is the first paragraph.")
    .Newline()
    .AddText("This is a second line. ")
    .AddText("It includes some ")
    .AddText("large", new Formatting {Font = new FontFamily("Times New Roman"), FontSize = 32})
    .AddText(", blue", new Formatting {Color = Color.Blue})
    .AddText(", bold text.", new Formatting {Bold = true})
    .Newline()
    .AddText("And finally some normal text.");

The above code will create a single paragraph with colors and various fonts. You can add multiple paragraphs by chaining to other Add methods, or add an empty paragraph with the document AddParagraph method as shown below.

document.AddParagraph()
    .AddText("This sets the text of the paragraph")
    .Add("This adds a second paragraph")
    .Add("And a third.");

// Can add multiple paragraphs with AddRange
document.AddRange(new[] { "This is a paragraph", "This is too."});

// Can also create paragraphs directly. And use new C# features to condense code
document.Add(new Paragraph("I am centered 20pt Comic Sans.", new() { Font = new FontFamily("Comic Sans MS"), FontSize = 20 }) 
        { Properties = new() { Alignment = Alignment.Center } });

You can set specific styles and highlight text

document.Add("Highlighted text").Style(HeadingType.Heading2);
document.Add("First line. ")
    .AddText("This sentence is highlighted", new() { Highlight = Highlight.Yellow })
    .AddText(", but this is ")
    .AddText("not", new() { Italic = true })
    .AddText(".");

Or add line indents through the WithProperties method.

document.Add(new Paragraph("This paragraph has the first sentence indented. "
              + "It shows how you can use the Intent property to control how paragraphs are lined up.")
        { Properties = new() { FirstLineIndent = 20 } })
    .Newline()
    .AddText("This line shouldn't be indented - instead, it should start over on the left side.");

Page breaks

Add a page break with the AddPageBreak method.

document.AddPageBreak();

Finding and Replacing text

IDocument has methods to locate text by string or Regex and optionally replace it. These methods walk through all paragraphs across all sections.

IEnumerable<(Paragraph owner, int position)> results = document.FindText("look for me", StringComparison.CurrentCulture);
 ...
IEnumerable<(Paragraph owner, int position)> results = document.FindPattern(new Regex("^The"));


bool foundText = document.FindReplace("original text", "replacement text", StringComparison.CurrentCulture);
 ...

// Can remove located text
document.FindReplace("original text", null, StringComparison.CurrentCulture);

Paragraph has similar methods which are scoped to that paragraph.

IEnumerable<int position> results = paragraph.FindText("look for me", StringComparison.CurrentCulture);
 ...
IEnumerable<int position> results = paragraph.FindPattern(new Regex("^The"));
 ...
bool foundText = paragraph.FindReplace("original text", "replacement text", StringComparison.CurrentCulture);

Hyperlinks

Hyperlinks can be added to paragraphs - this creates a clickable element which can point to an external source, or to a section of the document.

var paragraph = document.Add("This line contains a ")
    .Add(new Hyperlink("hyperlink", new Uri("http://www.microsoft.com")))
    .AddText(". Here's a .");

// Insert another hyperlink into the paragraph.
paragraph.Insert(p.Text.Length - 2, new Hyperlink("second link", new Uri("http://docs.microsoft.com/")));

Images

Images such as .png, .jpg, or .tiff can be inserted into the document. The binary image data must be added to the document first - it's stored as a blob which can then be inserted zero or more times into paragraphs. Each time you insert the image, it's wrapped in a Picture object. The picture has properties to control the size, shape, rotation, etc. which are all applied to the image data for that specific render. The picture, in turn, is held in a Drawing element which is what actually gets inserted into the Run. Here's the relationship structure:

Run
 |
 +--- Drawing
        |
        +--- Picture
                |
                +----> Image (.bmp, .jpg, etc.)

Inserting an image involves three steps:

  1. Create an Image object that wraps an image file (.png, .jpeg, etc.)
  2. Create a Picture object from the image to set attributes such as shape, size, and rotation.
  3. Insert the picture into a paragraph. This will automatically wrap the picture in a Drawing.
// Add an image into the document.
var image = document.Creat
View on GitHub
GitHub Stars6
CategoryDevelopment
Updated8mo ago
Forks0

Languages

C#

Security Score

77/100

Audited on Aug 8, 2025

No findings