aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/mammoth/documents/NumberingLevel.java19
-rw-r--r--src/main/java/org/zwobble/mammoth/docx/Numbering.java19
-rw-r--r--src/main/java/org/zwobble/mammoth/docx/NumberingXml.java56
-rw-r--r--src/main/java/org/zwobble/mammoth/xml/NullXmlElement.java20
-rw-r--r--src/main/java/org/zwobble/mammoth/xml/XmlElement.java28
-rw-r--r--src/main/java/org/zwobble/mammoth/xml/XmlElementLike.java8
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java49
7 files changed, 194 insertions, 5 deletions
diff --git a/src/main/java/org/zwobble/mammoth/documents/NumberingLevel.java b/src/main/java/org/zwobble/mammoth/documents/NumberingLevel.java
new file mode 100644
index 0000000..ca134b9
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/documents/NumberingLevel.java
@@ -0,0 +1,19 @@
+package org.zwobble.mammoth.documents;
+
+public class NumberingLevel {
+ private final String levelIndex;
+ private final boolean isOrdered;
+
+ public NumberingLevel(String levelIndex, boolean isOrdered) {
+ this.levelIndex = levelIndex;
+ this.isOrdered = isOrdered;
+ }
+
+ public String getLevelIndex() {
+ return levelIndex;
+ }
+
+ public boolean isOrdered() {
+ return isOrdered;
+ }
+}
diff --git a/src/main/java/org/zwobble/mammoth/docx/Numbering.java b/src/main/java/org/zwobble/mammoth/docx/Numbering.java
new file mode 100644
index 0000000..43b3e56
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/docx/Numbering.java
@@ -0,0 +1,19 @@
+package org.zwobble.mammoth.docx;
+
+import org.zwobble.mammoth.documents.NumberingLevel;
+
+import java.util.Map;
+import java.util.Optional;
+
+public class Numbering {
+ private final Map<String, Map<String, NumberingLevel>> numbering;
+
+ public Numbering(Map<String, Map<String, NumberingLevel>> numbering) {
+ this.numbering = numbering;
+ }
+
+ public Optional<NumberingLevel> findLevel(String numId, String level) {
+ return Optional.ofNullable(numbering.get(numId))
+ .flatMap(levels -> Optional.ofNullable(levels.get(level)));
+ }
+}
diff --git a/src/main/java/org/zwobble/mammoth/docx/NumberingXml.java b/src/main/java/org/zwobble/mammoth/docx/NumberingXml.java
new file mode 100644
index 0000000..9c3e286
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/docx/NumberingXml.java
@@ -0,0 +1,56 @@
+package org.zwobble.mammoth.docx;
+
+import org.zwobble.mammoth.documents.NumberingLevel;
+import org.zwobble.mammoth.xml.XmlElement;
+import org.zwobble.mammoth.xml.XmlElementList;
+
+import java.util.Map;
+import java.util.Optional;
+
+import static com.google.common.collect.Maps.immutableEntry;
+import static org.zwobble.mammoth.util.MammothMaps.toMap;
+
+public class NumberingXml {
+ public static Numbering readNumberingXmlElement(XmlElement element) {
+ Map<String, Map<String, NumberingLevel>> abstractNums = readAbstractNums(element.findChildren("w:abstractNum"));
+ return new Numbering(readNums(element.findChildren("w:num"), abstractNums));
+ }
+
+ private static Map<String, Map<String, NumberingLevel>> readAbstractNums(XmlElementList children) {
+ return toMap(children, NumberingXml::readAbstractNum);
+ }
+
+ private static Map.Entry<String, Map<String, NumberingLevel>> readAbstractNum(XmlElement element) {
+ // TODO: in python-mammoth, we allow None here. Check whether that's actually possible or not
+ String abstractNumId = element.getAttribute("w:abstractNumId");
+ return immutableEntry(abstractNumId, readAbstractNumLevels(element));
+ }
+
+ private static Map<String, NumberingLevel> readAbstractNumLevels(XmlElement element) {
+ return toMap(element.findChildren("w:lvl"), NumberingXml::readAbstractNumLevel);
+ }
+
+ private static Map.Entry<String, NumberingLevel> readAbstractNumLevel(XmlElement element) {
+ String levelIndex = element.getAttribute("w:ilvl");
+ Optional<String> numFmt = element.findChildOrEmpty("w:numFmt").getAttributeOrNone("w:val");
+ boolean isOrdered = !numFmt.equals(Optional.of("bullet"));
+ return immutableEntry(levelIndex, new NumberingLevel(levelIndex, isOrdered));
+ }
+
+ private static Map<String, Map<String, NumberingLevel>> readNums(
+ XmlElementList numElements,
+ Map<String, Map<String, NumberingLevel>> abstractNums
+ ) {
+ return toMap(numElements, numElement -> readNum(numElement, abstractNums));
+ }
+
+ private static Map.Entry<String,Map<String,NumberingLevel>> readNum(
+ XmlElement numElement,
+ Map<String, Map<String, NumberingLevel>> abstractNums
+ ) {
+ // TODO: in python-mammoth, we allow None here. Check whether that's actually possible or not
+ String numId = numElement.getAttribute("w:numId");
+ String abstractNumId = numElement.findChild("w:abstractNumId").getAttribute("w:val");
+ return immutableEntry(numId, Optional.ofNullable(abstractNums.get(abstractNumId)).get());
+ }
+}
diff --git a/src/main/java/org/zwobble/mammoth/xml/NullXmlElement.java b/src/main/java/org/zwobble/mammoth/xml/NullXmlElement.java
new file mode 100644
index 0000000..05bfa78
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/xml/NullXmlElement.java
@@ -0,0 +1,20 @@
+package org.zwobble.mammoth.xml;
+
+import java.util.Optional;
+
+public class NullXmlElement implements XmlElementLike {
+ public static final XmlElementLike INSTANCE = new NullXmlElement();
+
+ private NullXmlElement() {
+ }
+
+ @Override
+ public XmlElementLike findChildOrEmpty(String name) {
+ return this;
+ }
+
+ @Override
+ public Optional<String> getAttributeOrNone(String name) {
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlElement.java b/src/main/java/org/zwobble/mammoth/xml/XmlElement.java
index a42a1b7..8c3a011 100644
--- a/src/main/java/org/zwobble/mammoth/xml/XmlElement.java
+++ b/src/main/java/org/zwobble/mammoth/xml/XmlElement.java
@@ -2,15 +2,15 @@ package org.zwobble.mammoth.xml;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.getFirst;
-public class XmlElement implements XmlNode {
+public class XmlElement implements XmlNode, XmlElementLike {
public XmlElement(String name) {
this(name, ImmutableMap.of());
}
@@ -39,7 +39,12 @@ public class XmlElement implements XmlNode {
public String getAttribute(String name) {
// TODO: throw more informative error message
- return Optional.ofNullable(attributes.get(name)).get();
+ return getAttributeOrNone(name).get();
+ }
+
+ @Override
+ public Optional<String> getAttributeOrNone(String name) {
+ return Optional.ofNullable(attributes.get(name));
}
public List<XmlNode> getChildren() {
@@ -62,9 +67,22 @@ public class XmlElement implements XmlNode {
}
public XmlElementList findChildren(String name) {
- Iterable<XmlElement> filtered = filter(
+ Iterable<XmlElement> filtered = findChildrenIterable(name);
+ return new XmlElementList(ImmutableList.copyOf(filtered));
+ }
+
+ public XmlElement findChild(String name) {
+ return findChildrenIterable(name).iterator().next();
+ }
+
+ @Override
+ public XmlElementLike findChildOrEmpty(String name) {
+ return getFirst(findChildrenIterable(name), NullXmlElement.INSTANCE);
+ }
+
+ private Iterable<XmlElement> findChildrenIterable(String name) {
+ return filter(
filter(children, XmlElement.class),
child -> child.getName().equals(name));
- return new XmlElementList(ImmutableList.copyOf(filtered));
}
}
diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlElementLike.java b/src/main/java/org/zwobble/mammoth/xml/XmlElementLike.java
new file mode 100644
index 0000000..06193a7
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/xml/XmlElementLike.java
@@ -0,0 +1,8 @@
+package org.zwobble.mammoth.xml;
+
+import java.util.Optional;
+
+public interface XmlElementLike {
+ XmlElementLike findChildOrEmpty(String name);
+ Optional<String> getAttributeOrNone(String name);
+}
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java
new file mode 100644
index 0000000..a10575f
--- /dev/null
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/NumberingXmlTests.java
@@ -0,0 +1,49 @@
+package org.zwobble.mammoth.tests.docx;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.junit.Test;
+import org.zwobble.mammoth.docx.Numbering;
+import org.zwobble.mammoth.xml.XmlElement;
+
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.zwobble.mammoth.docx.NumberingXml.readNumberingXmlElement;
+import static org.zwobble.mammoth.xml.XmlNodes.element;
+
+public class NumberingXmlTests {
+ private final static XmlElement SAMPLE_NUMBERING_XML = element("w:numbering", ImmutableList.of(
+ element("w:abstractNum", ImmutableMap.of("w:abstractNumId", "42"), ImmutableList.of(
+ element("w:lvl", ImmutableMap.of("w:ilvl", "0"), ImmutableList.of(
+ element("w:numFmt", ImmutableMap.of("w:val", "bullet")))),
+ element("w:lvl", ImmutableMap.of("w:ilvl", "1"), ImmutableList.of(
+ element("w:numFmt", ImmutableMap.of("w:val", "decimal")))))),
+ element("w:num", ImmutableMap.of("w:numId", "47"), ImmutableList.of(
+ element("w:abstractNumId", ImmutableMap.of("w:val", "42"))))));
+
+ @Test
+ public void findLevelReturnsNoneIfNumWithIdCannotBeFound() {
+ Numbering numbering = readNumberingXmlElement(element("w:numbering"));
+ assertEquals(Optional.empty(), numbering.findLevel("47", "0"));
+ }
+
+ @Test
+ public void levelIncludesLevelIndex() {
+ Numbering numbering = readNumberingXmlElement(SAMPLE_NUMBERING_XML);
+ assertEquals("0", numbering.findLevel("47", "0").get().getLevelIndex());
+ assertEquals("1", numbering.findLevel("47", "1").get().getLevelIndex());
+ }
+
+ @Test
+ public void listIsNotOrderedIfFormattedAsBullet() {
+ Numbering numbering = readNumberingXmlElement(SAMPLE_NUMBERING_XML);
+ assertEquals(false, numbering.findLevel("47", "0").get().isOrdered());
+ }
+
+ @Test
+ public void listIsOrderedIfFormattedAsDecimal() {
+ Numbering numbering = readNumberingXmlElement(SAMPLE_NUMBERING_XML);
+ assertEquals(true, numbering.findLevel("47", "1").get().isOrdered());
+ }
+}