Fb2.Document
| Language | C# (.NET 10; older package versions for .NET 8 and .NET Standard 2.0) |
|---|---|
| License | MIT |
| Repository | github.com/Overrided/Fb2.Document |
| Documentation | README |
| Depends on | nothing outside .NET |
| Read / write | yes / yes |
Fb2.Document loads an FB2 file into a tree of typed nodes that mirrors the FictionBook schema: FictionBook, BookDescription, TitleInfo, BookBody, BodySection, Paragraph, Emphasis, BinaryImage and so on. Containers (Fb2Container) hold child nodes and text elements (Fb2Element) hold strings. You can query the tree (GetChildren, GetDescendants, GetFirstDescendant), edit it with chainable methods, and serialize it back to XML.
The loader doesn’t validate against the XSD, because many FB2 files in the wild are not fully valid: unknown nodes and attributes are skipped, and misplaced elements are kept but marked IsUnsafe. Loading from a Stream lets the XML reader honor the encoding in the XML declaration (for example windows-1251); loading from a string keeps the text as you decoded it.
Installation#
dotnet add package Fb2.Document
Version 2.5 targets .NET 10, 2.4.x targets .NET 8, and 1.3.1 targets .NET Standard 2.0.
Basic usage: read metadata and text#
using Fb2.Document;
using Fb2.Document.Models;
var doc = new Fb2Document();
using (var stream = File.OpenRead("book.fb2"))
{
doc.Load(stream); // encoding-safe
}
TitleInfo? info = doc.Title;
Console.WriteLine("Title: " + info?.GetFirstChild<BookTitle>()?.Content);
foreach (Author author in info?.GetChildren<Author>() ?? [])
{
var first = author.GetFirstChild<FirstName>()?.Content;
var last = author.GetFirstChild<LastName>()?.Content;
Console.WriteLine($"Author: {first} {last}");
}
Console.WriteLine("Language: " + info?.GetFirstChild<Lang>()?.Content);
// main body text: ToString() returns the text content of a node
BookBody body = doc.Bodies[0];
foreach (BodySection section in body.GetChildren<BodySection>())
{
Console.WriteLine("== " + section.GetFirstChild<Title>()?.ToString().Trim());
foreach (Paragraph p in section.GetDescendants<Paragraph>())
Console.WriteLine(p.ToString());
}
How to extract images from an FB2 file#
Images are BinaryImage elements with Base64 content:
using Fb2.Document.Constants;
Directory.CreateDirectory("images");
foreach (BinaryImage image in doc.BinaryImages)
{
string id = image.GetAttribute(AttributeNames.Id)?.Value ?? Guid.NewGuid().ToString();
byte[] data = Convert.FromBase64String(image.Content);
File.WriteAllBytes(Path.Combine("images", id), data);
}
The cover is the image referenced from title-info/coverpage.
How to find all footnotes#
Notes live in a second body with name="notes":
var notes = doc.Bodies.FirstOrDefault(b =>
b.GetAttribute(AttributeNames.Name)?.Value == "notes");
foreach (BodySection note in notes?.GetChildren<BodySection>() ?? [])
{
string? id = note.GetAttribute(AttributeNames.Id)?.Value;
Console.WriteLine($"{id}: {note.ToString().Trim()}");
}
How to add a paragraph and save the FB2 file#
BodySection first = doc.Bodies[0].GetFirstChild<BodySection>()!;
first.AddContent(new Paragraph()
.AddTextContent("A new paragraph with ")
.AddContent(new Strong().AddTextContent("bold"))
.AddTextContent(" text."));
string? xml = doc.ToXmlString();
File.WriteAllText("out.fb2", xml);
ToXml() returns an XDocument instead of a string.
How to load an FB2 from a .fb2.zip archive#
using System.IO.Compression;
using ZipArchive zip = ZipFile.OpenRead("book.fb2.zip");
ZipArchiveEntry entry = zip.Entries.First(e => e.Name.EndsWith(".fb2", StringComparison.OrdinalIgnoreCase));
using Stream s = entry.Open();
var doc = new Fb2Document();
await doc.LoadAsync(s);
Tips#
- On .NET (Core), windows-1251 and other legacy code pages need
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);once at startup, or loading such files fails. - Loading errors throw
Fb2DocumentLoadingException; catch it when processing collections of files. Fb2.Document.ExtensionsaddsAppendContent,AppendAttributeand similar methods that keep the node’s concrete type during method chaining.ElementNamesandAttributeNameslist every element and attribute the library accepts.