1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.parser;
20
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.function.UnaryOperator;
27
28 import org.apache.maven.doxia.sink.Sink;
29 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
30 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
31
32
33
34
35
36
37
38
39
40
41 public class Xhtml1BaseParser extends Xhtml5BaseParser {
42
43 private static final class AttributeMapping {
44 private final String sourceName;
45 private final String targetName;
46 private final UnaryOperator<String> valueMapper;
47 private final MergeSemantics mergeSemantics;
48
49 enum MergeSemantics {
50 OVERWRITE,
51 IGNORE,
52 PREPEND
53 }
54
55 AttributeMapping(String sourceAttribute, String targetAttribute, MergeSemantics mergeSemantics) {
56 this(sourceAttribute, targetAttribute, UnaryOperator.identity(), mergeSemantics);
57 }
58
59 AttributeMapping(
60 String sourceName,
61 String targetName,
62 UnaryOperator<String> valueMapper,
63 MergeSemantics mergeSemantics) {
64 super();
65 this.sourceName = sourceName;
66 this.targetName = targetName;
67 this.valueMapper = valueMapper;
68 this.mergeSemantics = mergeSemantics;
69 }
70
71 public String getSourceName() {
72 return sourceName;
73 }
74
75 public String getTargetName() {
76 return targetName;
77 }
78
79 public UnaryOperator<String> getValueMapper() {
80 return valueMapper;
81 }
82
83 public String mergeValue(String oldValue, String newValue) {
84 final String mergedValue;
85 switch (mergeSemantics) {
86 case IGNORE:
87 mergedValue = oldValue;
88 break;
89 case OVERWRITE:
90 mergedValue = newValue;
91 break;
92 default:
93 mergedValue = newValue + " " + oldValue;
94 }
95 return mergedValue;
96 }
97 }
98
99 static final String mapAlignToStyle(String alignValue) {
100 switch (alignValue) {
101 case "center":
102 case "left":
103 case "right":
104 return "text-align: " + alignValue + ";";
105 default:
106 return null;
107 }
108 }
109
110
111
112
113 private static final Map<String, Collection<AttributeMapping>> ATTRIBUTE_MAPPING_TABLE = new HashMap<>();
114
115
116
117
118 private static final Map<String, String> ELEMENT_MAPPING_TABLE = new HashMap<>();
119
120 static {
121 ATTRIBUTE_MAPPING_TABLE.put(
122 "a", Collections.singleton(new AttributeMapping("name", "id", AttributeMapping.MergeSemantics.IGNORE)));
123
124 Collection<AttributeMapping> tableMappings = Arrays.asList(
125 new AttributeMapping(
126 "border",
127 "class",
128 (v) -> (v != null && !v.equals("0")) ? "bodyTableBorder" : null,
129 AttributeMapping.MergeSemantics.PREPEND),
130 new AttributeMapping(
131 "align", "style", Xhtml1BaseParser::mapAlignToStyle, AttributeMapping.MergeSemantics.PREPEND));
132 ATTRIBUTE_MAPPING_TABLE.put("table", tableMappings);
133 ATTRIBUTE_MAPPING_TABLE.put(
134 "td",
135 Collections.singleton(new AttributeMapping(
136 "align", "style", Xhtml1BaseParser::mapAlignToStyle, AttributeMapping.MergeSemantics.PREPEND)));
137 ATTRIBUTE_MAPPING_TABLE.put(
138 "th",
139 Collections.singleton(new AttributeMapping(
140 "align", "style", Xhtml1BaseParser::mapAlignToStyle, AttributeMapping.MergeSemantics.PREPEND)));
141 ELEMENT_MAPPING_TABLE.put("tt", "code");
142 ELEMENT_MAPPING_TABLE.put("strike", "del");
143 }
144
145
146
147
148 @Override
149 protected boolean baseStartTag(XmlPullParser parser, Sink sink) {
150 SinkEventAttributeSet attribs = getAttributesFromParser(parser);
151 String elementName = parser.getName();
152 Collection<AttributeMapping> attributeMappings = ATTRIBUTE_MAPPING_TABLE.get(elementName);
153 if (attributeMappings != null) {
154 for (AttributeMapping attributeMapping : attributeMappings) {
155 String attributeValue = (String) attribs.getAttribute(attributeMapping.getSourceName());
156 if (attributeValue != null) {
157 String newValue = attributeMapping.getValueMapper().apply(attributeValue);
158 if (newValue != null) {
159 String oldValue = (String) attribs.getAttribute(attributeMapping.getTargetName());
160 if (oldValue != null) {
161 newValue = attributeMapping.mergeValue(oldValue, newValue);
162 }
163 attribs.addAttribute(attributeMapping.getTargetName(), newValue);
164 }
165 attribs.removeAttribute(attributeMapping.getSourceName());
166 }
167 }
168 }
169 String mappedElementName = ELEMENT_MAPPING_TABLE.getOrDefault(elementName, elementName);
170 return super.baseStartTag(mappedElementName, attribs, sink);
171 }
172
173 @Override
174 protected boolean baseEndTag(XmlPullParser parser, Sink sink) {
175 SinkEventAttributeSet attribs = getAttributesFromParser(parser);
176 String elementName = parser.getName();
177 String mappedElementName = ELEMENT_MAPPING_TABLE.getOrDefault(elementName, elementName);
178 return super.baseEndTag(mappedElementName, attribs, sink);
179 }
180 }