diff --git a/examples/Demo/Program.cs b/examples/Demo/Program.cs
index d1ee82e..fccd469 100644
--- a/examples/Demo/Program.cs
+++ b/examples/Demo/Program.cs
@@ -12,7 +12,7 @@ static class Program
static async Task Main(string[] args)
{
const string filename = "test.docx";
- string html = ResourceHelper.GetString("Resources.CompleteRunTest.html");
+ string html = ResourceHelper.GetString("Resources.UlStyles.html");
if (File.Exists(filename)) File.Delete(filename);
using (MemoryStream generatedDocument = new())
diff --git a/examples/Demo/Resources/UlStyles.html b/examples/Demo/Resources/UlStyles.html
new file mode 100644
index 0000000..bfe2fc6
--- /dev/null
+++ b/examples/Demo/Resources/UlStyles.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
index 9ce33e3..199d0ae 100644
--- a/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
+++ b/src/Html2OpenXml/Expressions/Numbering/ListExpression.cs
@@ -38,7 +38,7 @@ readonly struct ListContext(string listName, int absNumId, int instanceId, int l
// https://answers.microsoft.com/en-us/msoffice/forum/all/custom-list-number-style/21a54399-4404-4c37-8843-2ccaaf827485
// Image bullet: http://officeopenxml.com/WPnumbering-imagesAsSymbol.php
private static readonly HashSet supportedListTypes =
- ["disc", "decimal", "square", "circle",
+ ["disc", "decimal", "square", "circle", "dash",
"lower-alpha", "upper-alpha", "lower-latin", "upper-latin",
"lower-greek", "upper-greek",
"lower-roman", "upper-roman",
@@ -227,7 +227,15 @@ private static string GetListName(IElement listNode, string? parentName = null)
if (parentName != null && IsCascadingStyle(parentName))
return parentName!;
- type = orderedList? "decimal" : "disc";
+ // If a specific list-style-type is provided for an unordered list (e.g., a custom string like "'-'"),
+ // we strip the surrounding quotes to extract the raw symbol.
+ // Otherwise, we fallback to the default "decimal" or "disc" styles.
+ if (!orderedList && !string.IsNullOrEmpty(type))
+ {
+ return type!.Trim('\'', '\"');
+ }
+
+ return orderedList ? "decimal" : "disc";
}
return type!;
diff --git a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs
index b41c4ee..95c953c 100644
--- a/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs
+++ b/src/Html2OpenXml/Expressions/Numbering/NumberingExpressionBase.cs
@@ -50,8 +50,20 @@ protected int GetOrCreateListTemplate(ParsingContext context, string listName)
Numbering numberingPart = context.MainPart.NumberingDefinitionsPart!.Numbering!;
+ AbstractNum abstractNum;
+
// at this stage, we have sanitized the list style so it's safe to grab them from the predefined template lists
- var abstractNum = predefinedNumberingLists[listName];
+ if (predefinedNumberingLists.TryGetValue(listName, out var predefined))
+ {
+ // If it's a predefined style, we clone it as usual
+ abstractNum = (AbstractNum)predefined.CloneNode(true);
+ }
+ else
+ {
+ // If not found in predefined lists, listName contains a custom bullet character (e.g., "-")
+ abstractNum = CreateCustomBulletAbstractNum(listName);
+ }
+
abstractNum = (AbstractNum) abstractNum.CloneNode(true);
abstractNum.AbstractNumberId = IncrementAbstractNumId(context, numberingPart);
var level1 = abstractNum.GetFirstChild()!;
@@ -216,6 +228,38 @@ private void InitNumberingIds(ParsingContext context)
isInitialized = true;
}
+ ///
+ /// Generates a custom abstract numbering definition for unordered lists using a specific symbol.
+ ///
+ /// The custom character or string to be used as the list bullet.
+ /// An instance configured with the custom bullet symbol across all levels.
+ private AbstractNum CreateCustomBulletAbstractNum(string customSymbol)
+ {
+ var abstractNum = new AbstractNum {
+ AbstractNumDefinitionName = new() { Val = customSymbol },
+ MultiLevelType = new() { Val = MultiLevelValues.HybridMultilevel }
+ };
+
+ for (var lvlIndex = 0; lvlIndex <= MaxLevel; lvlIndex++)
+ {
+ abstractNum.Append(new Level {
+ StartNumberingValue = new() { Val = 1 },
+ NumberingFormat = new() { Val = NumberFormatValues.Bullet },
+ LevelIndex = lvlIndex,
+ LevelText = new() { Val = string.Format(customSymbol, lvlIndex+1) },
+ LevelJustification = new() { Val = LevelJustificationValues.Left },
+ PreviousParagraphProperties = new() {
+ Indentation = new() {
+ Left = ((lvlIndex + 1) * Indentation * 2).ToString(),
+ Hanging = Indentation.ToString()
+ }
+ }
+ });
+ }
+
+ return abstractNum;
+ }
+
///
/// Predefined template of lists.
///
@@ -230,6 +274,7 @@ private static IReadOnlyDictionary InitKnownLists()
("disc", NumberFormatValues.Bullet, "•"),
("square", NumberFormatValues.Bullet, "▪"),
("circle", NumberFormatValues.Bullet, "o"),
+ ("dash", NumberFormatValues.Bullet, "-"),
("upper-alpha", NumberFormatValues.UpperLetter, "%{0}."),
("lower-alpha", NumberFormatValues.LowerLetter, "%{0}."),
("upper-roman", NumberFormatValues.UpperRoman, "%{0}."),
@@ -299,4 +344,4 @@ private static IReadOnlyDictionary InitKnownLists()
return knownAbstractNums;
#endif
}
-}
\ No newline at end of file
+}