diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-08-09 15:03:03 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-08-09 15:03:03 +0100 |
| commit | 014e7ef150a860f06323692ceaa5a9f21874f678 (patch) | |
| tree | f25bc0149cda20d5a2b6300faa6b940f145325d7 /src | |
| parent | 227d04c7c302fbf38d4b2501090078377b1bcfd1 (diff) | |
Ignore numbering levels that use numStyleLink to refer to themselves
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java | 13 | ||||
| -rw-r--r-- | src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java | 21 |
2 files changed, 33 insertions, 1 deletions
diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java b/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java index 1a39047..6213d13 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java @@ -4,8 +4,10 @@ import org.zwobble.mammoth.internal.documents.NumberingLevel; import org.zwobble.mammoth.internal.util.Iterables; import org.zwobble.mammoth.internal.util.Maps; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import static org.zwobble.mammoth.internal.util.Maps.lookup; import static org.zwobble.mammoth.internal.util.Maps.map; @@ -86,6 +88,15 @@ public class Numbering { } public Optional<NumberingLevel> findLevel(String numId, String level) { + return findLevelWithSeenNumIds(numId, level, new HashSet<>()); + } + + public Optional<NumberingLevel> findLevelWithSeenNumIds(String numId, String level, Set<String> seenNumIds) { + if (seenNumIds.contains(numId)) { + return Optional.empty(); + } + seenNumIds.add(numId); + return lookup(nums, numId) .flatMap(num -> num.abstractNumId) .flatMap(abstractNumId -> lookup(this.abstractNums, abstractNumId)) @@ -94,7 +105,7 @@ public class Numbering { return abstractNum.numStyleLink .flatMap(numStyleLink -> styles.findNumberingStyleById(numStyleLink)) .flatMap(style -> style.getNumId()) - .flatMap(linkedNumId -> findLevel(linkedNumId, level)); + .flatMap(linkedNumId -> findLevelWithSeenNumIds(linkedNumId, level, seenNumIds)); } else { return lookup(abstractNum.levels, level).map(value -> value.toNumberingLevel()); } diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java index 676b654..a95e50e 100644 --- a/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java @@ -167,6 +167,27 @@ public class NumberingXmlTests { assertEquals(true, numbering.findLevel("201", "0").get().isOrdered()); } + @Test + public void whenAbstractNumHasSelfRecursiveNumStyleLinkThenLevelIsNotFound() { + Numbering numbering = readNumberingXmlElement( + element("w:numbering", list( + element("w:abstractNum", map("w:abstractNumId", "100"), list( + element("w:numStyleLink", map("w:val", "List1")) + )), + element("w:num", map("w:numId", "200"), list( + element("w:abstractNumId", map("w:val", "100")) + )) + )), + new Styles( + map(), + map(), + map(), + map("List1", new NumberingStyle(Optional.of("200"))) + ) + ); + assertEquals(Optional.empty(), numbering.findLevel("200", "0")); + } + // See: 17.9.23 pStyle (Paragraph Style's Associated Numbering Level) in ECMA-376, 4th Edition @Test public void numberingLevelCanBeFoundByParagraphStyleId() { |
