Skip to content

Commit b65bc06

Browse files
committed
Ignore style definitions using a style ID that has already been used
1 parent dd25b82 commit b65bc06

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 1.11.0
2+
3+
* Ignore style definitions using a style ID that has already been used.
4+
15
# 1.10.0
26

37
* Add "Heading" and "Body" styles, as found in documents created by Apple Pages,

src/main/java/org/zwobble/mammoth/internal/docx/StylesXml.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
import java.util.Optional;
1010

1111
import static org.zwobble.mammoth.internal.util.Iterables.lazyFilter;
12-
import static org.zwobble.mammoth.internal.util.Maps.entry;
13-
import static org.zwobble.mammoth.internal.util.Maps.toMap;
12+
import static org.zwobble.mammoth.internal.util.Maps.*;
1413

1514
public class StylesXml {
1615
public static Styles readStylesXmlElement(XmlElement element) {
@@ -24,7 +23,7 @@ public static Styles readStylesXmlElement(XmlElement element) {
2423
}
2524

2625
private static Map<String, Style> readStyles(XmlElementList styleElements, String styleType) {
27-
return toMap(
26+
return toMapPreferFirst(
2827
styleElementsOfType(styleElements, styleType),
2928
StylesXml::readStyle
3029
);
@@ -37,7 +36,7 @@ private static Map.Entry<String, Style> readStyle(XmlElement element) {
3736
}
3837

3938
private static Map<String, NumberingStyle> readNumberingStyles(XmlElementList styleElements) {
40-
return toMap(
39+
return toMapPreferFirst(
4140
styleElementsOfType(styleElements, "numbering"),
4241
StylesXml::readNumberingStyle
4342
);

src/main/java/org/zwobble/mammoth/internal/util/Maps.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ public static <T, K, V> Map<K, V> toMap(Iterable<T> iterable, Function<T, Map.En
6363
return map;
6464
}
6565

66+
/**
67+
* Convert an iterable to map using the given mapping function. If the
68+
* mapping function generates entries with the same key, only the first
69+
* entry will be used, and subsequent entries will be ignored.
70+
*/
71+
public static <T, K, V> Map<K, V> toMapPreferFirst(Iterable<T> iterable, Function<T, Map.Entry<K, V>> function) {
72+
Map<K, V> map = new HashMap<>();
73+
for (T element : iterable) {
74+
Map.Entry<K, V> entry = function.apply(element);
75+
if (!map.containsKey(entry.getKey())) {
76+
map.put(entry.getKey(), entry.getValue());
77+
}
78+
}
79+
return map;
80+
}
81+
6682
public static <T, K> Map<K, List<T>> toMultiMapWithKey(Iterable<T> iterable, Function<T, K> function) {
6783
return toMultiMap(iterable, element -> entry(function.apply(element), element));
6884
}

src/test/java/org/zwobble/mammoth/tests/docx/StylesXmlTests.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,46 @@ public void numberingStyleHasNumIdReadFromParagraphProperties() {
118118
assertEquals(Optional.of("42"), styles.findNumberingStyleById("List1").get().getNumId());
119119
}
120120

121+
@Test
122+
public void whenMultipleNonNumberingStyleElementsHaveSameStyleIdThenOnlyFirstElementIsUsed() {
123+
XmlElement element = element("w:styles", list(
124+
element("w:style", map("w:type", "table", "w:styleId", "TableNormal"), list(
125+
nameElement("Normal Table")
126+
)),
127+
element("w:style", map("w:type", "table", "w:styleId", "TableNormal"), list(
128+
nameElement("Table Normal")
129+
))
130+
));
131+
132+
Styles styles = readStylesXmlElement(element);
133+
134+
assertEquals(Optional.of("Normal Table"), styles.findTableStyleById("TableNormal").get().getName());
135+
}
136+
137+
@Test
138+
public void whenMultipleNumberingStyleElementsHaveSameStyleIdThenOnlyFirstElementIsUsed() {
139+
XmlElement element = element("w:styles", list(
140+
element("w:style", map("w:type", "numbering", "w:styleId", "List1"), list(
141+
element("w:pPr", list(
142+
element("w:numPr", list(
143+
element("w:numId", map("w:val", "42"))
144+
))
145+
))
146+
)),
147+
element("w:style", map("w:type", "numbering", "w:styleId", "List1"), list(
148+
element("w:pPr", list(
149+
element("w:numPr", list(
150+
element("w:numId", map("w:val", "43"))
151+
))
152+
))
153+
))
154+
));
155+
156+
Styles styles = readStylesXmlElement(element);
157+
158+
assertEquals(Optional.of("42"), styles.findNumberingStyleById("List1").get().getNumId());
159+
}
160+
121161
private XmlElement nameElement(String name) {
122162
return element("w:name", map("w:val", name));
123163
}

0 commit comments

Comments
 (0)