From 437a3029d872ec5f2113aa6e074567de7fd2d61f Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 9 Jan 2021 17:25:55 +0000 Subject: Support numbering defined by paragraph style --- .../zwobble/mammoth/internal/docx/Numbering.java | 41 ++++++++++++++++++++-- .../mammoth/internal/docx/NumberingXml.java | 8 ++--- .../internal/docx/StatefulBodyXmlReader.java | 13 +++++-- 3 files changed, 52 insertions(+), 10 deletions(-) (limited to 'src/main/java/org') 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 90ea5c1..8d29393 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/Numbering.java @@ -4,21 +4,47 @@ import org.zwobble.mammoth.internal.documents.NumberingLevel; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import static org.zwobble.mammoth.internal.util.Maps.lookup; import static org.zwobble.mammoth.internal.util.Maps.map; public class Numbering { + public static class AbstractNum { - private final Map levels; + private final Map levels; private final Optional numStyleLink; - public AbstractNum(Map levels, Optional numStyleLink) { + public AbstractNum(Map levels, Optional numStyleLink) { this.levels = levels; this.numStyleLink = numStyleLink; } } + public static class AbstractNumLevel { + public static AbstractNumLevel ordered(String levelIndex) { + return new AbstractNumLevel(levelIndex, true, Optional.empty()); + } + + public static AbstractNumLevel unordered(String levelIndex) { + return new AbstractNumLevel(levelIndex, false, Optional.empty()); + } + + private final String levelIndex; + private final boolean isOrdered; + private final Optional paragraphStyleId; + + public AbstractNumLevel(String levelIndex, boolean isOrdered, Optional paragraphStyleId) { + this.levelIndex = levelIndex; + this.isOrdered = isOrdered; + this.paragraphStyleId = paragraphStyleId; + } + + public NumberingLevel toNumberingLevel() { + return new NumberingLevel(levelIndex, isOrdered); + } + } + public static class Num { private final Optional abstractNumId; @@ -30,6 +56,7 @@ public class Numbering { public static final Numbering EMPTY = new Numbering(map(), map(), Styles.EMPTY); private final Map abstractNums; + private final Map levelsByParagraphStyleId; private final Map nums; private final Styles styles; @@ -39,6 +66,10 @@ public class Numbering { Styles styles ) { this.abstractNums = abstractNums; + this.levelsByParagraphStyleId = abstractNums.values().stream() + .flatMap(abstractNum -> abstractNum.levels.values().stream()) + .filter(level -> level.paragraphStyleId.isPresent()) + .collect(Collectors.toMap(level -> level.paragraphStyleId.get(), level -> level)); this.nums = nums; this.styles = styles; } @@ -54,8 +85,12 @@ public class Numbering { .flatMap(style -> style.getNumId()) .flatMap(linkedNumId -> findLevel(linkedNumId, level)); } else { - return lookup(abstractNum.levels, level); + return lookup(abstractNum.levels, level).map(value -> value.toNumberingLevel()); } }); } + + public Optional findLevelByParagraphStyleId(String styleId) { + return lookup(levelsByParagraphStyleId, styleId).map(value -> value.toNumberingLevel()); + } } diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/NumberingXml.java b/src/main/java/org/zwobble/mammoth/internal/docx/NumberingXml.java index b25ffdd..5f811db 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/NumberingXml.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/NumberingXml.java @@ -1,6 +1,5 @@ package org.zwobble.mammoth.internal.docx; -import org.zwobble.mammoth.internal.documents.NumberingLevel; import org.zwobble.mammoth.internal.xml.XmlElement; import org.zwobble.mammoth.internal.xml.XmlElementList; @@ -31,15 +30,16 @@ public class NumberingXml { return entry(abstractNumId, abstractNum); } - private static Map readAbstractNumLevels(XmlElement element) { + private static Map readAbstractNumLevels(XmlElement element) { return toMap(element.findChildren("w:lvl"), NumberingXml::readAbstractNumLevel); } - private static Map.Entry readAbstractNumLevel(XmlElement element) { + private static Map.Entry readAbstractNumLevel(XmlElement element) { String levelIndex = element.getAttribute("w:ilvl"); Optional numFmt = element.findChildOrEmpty("w:numFmt").getAttributeOrNone("w:val"); boolean isOrdered = !numFmt.equals(Optional.of("bullet")); - return entry(levelIndex, new NumberingLevel(levelIndex, isOrdered)); + Optional paragraphStyleId = element.findChildOrEmpty("w:pStyle").getAttributeOrNone("w:val"); + return entry(levelIndex, new Numbering.AbstractNumLevel(levelIndex, isOrdered, paragraphStyleId)); } private static Map readNums(XmlElementList numElements) { diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java index 9c270de..0cf141e 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java @@ -256,12 +256,11 @@ class StatefulBodyXmlReader { private ReadResult readParagraph(XmlElement element) { XmlElementLike properties = element.findChildOrEmpty("w:pPr"); - Optional numbering = readNumbering(properties); ParagraphIndent indent = readParagraphIndent(properties); return ReadResult.map( readParagraphStyle(properties), readElements(element.getChildren()), - (style, children) -> new Paragraph(style, numbering, indent, children)).appendExtra(); + (style, children) -> new Paragraph(style, readNumbering(style, properties), indent, children)).appendExtra(); } private ReadResult readFieldChar(XmlElement element) { @@ -328,7 +327,15 @@ class StatefulBodyXmlReader { } - private Optional readNumbering(XmlElementLike properties) { + private Optional readNumbering(Optional