| 1 | package pro.verron.officestamper.api; | |
| 2 | ||
| 3 | import org.docx4j.openpackaging.packages.WordprocessingMLPackage; | |
| 4 | import org.docx4j.utils.TraversalUtilVisitor; | |
| 5 | import org.docx4j.wml.P; | |
| 6 | import pro.verron.officestamper.utils.wml.WmlUtils; | |
| 7 | ||
| 8 | import java.util.ArrayList; | |
| 9 | import java.util.List; | |
| 10 | import java.util.regex.Pattern; | |
| 11 | ||
| 12 | import static pro.verron.officestamper.utils.wml.WmlUtils.asString; | |
| 13 | import static pro.verron.officestamper.utils.wml.WmlUtils.insertSmartTag; | |
| 14 | ||
| 15 | /// The [PlaceholderHooker] class is a pre-processor that prepares inline placeholders in a `WordprocessingML` | |
| 16 | /// document. It searches for placeholders that match a given pattern and wraps them with a specified XML element to | |
| 17 | /// ensure proper processing by the OfficeStamper engine. | |
| 18 | /// | |
| 19 | /// This pre-processor is typically used to identify and mark inline expressions within paragraphs, making them | |
| 20 | /// recognizable for subsequent processing steps. | |
| 21 | public class PlaceholderHooker | |
| 22 | implements PreProcessor { | |
| 23 | ||
| 24 | private final Pattern pattern; | |
| 25 | private final String element; | |
| 26 | ||
| 27 | ||
| 28 | /// Constructs a new [PlaceholderHooker] instance with the specified regular expression and XML element | |
| 29 | /// name. | |
| 30 | /// | |
| 31 | /// @param regex the regular expression pattern used to identify inline placeholders in the document. This | |
| 32 | /// pattern should contain at least two capturing groups where the second group represents the actual | |
| 33 | /// placeholder content. | |
| 34 | /// @param element the name of the XML element to wrap around identified placeholders. This element will be | |
| 35 | /// used to mark the placeholders for further processing. | |
| 36 | public PlaceholderHooker(String regex, String element) { | |
| 37 | this(Pattern.compile(regex, Pattern.DOTALL), element); | |
| 38 | } | |
| 39 | ||
| 40 | ||
| 41 | /// Constructs a new [PlaceholderHooker] instance with the specified pattern and XML element name. | |
| 42 | /// | |
| 43 | /// @param pattern the compiled regular expression pattern used to identify inline placeholders in the | |
| 44 | /// document. This pattern should contain at least two capturing groups where the second group represents | |
| 45 | /// the actual placeholder content. | |
| 46 | /// @param element the name of the XML element to wrap around identified placeholders. This element will be | |
| 47 | /// used to mark the placeholders for further processing. | |
| 48 | public PlaceholderHooker(Pattern pattern, String element) { | |
| 49 | this.pattern = pattern; | |
| 50 | this.element = element; | |
| 51 | } | |
| 52 | ||
| 53 | @Override | |
| 54 | public void process(WordprocessingMLPackage document) { | |
| 55 | var visitor = new ParagraphCollector(pattern); | |
| 56 |
1
1. process : removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitDocument → KILLED |
WmlUtils.visitDocument(document, visitor); |
| 57 | for (var paragraph : visitor.paragraphs()) { | |
| 58 | var string = asString(paragraph); | |
| 59 | var matcher = pattern.matcher(string); | |
| 60 | // Iterates matches; replaces placeholder with a smart tag | |
| 61 |
1
1. process : negated conditional → KILLED |
while (matcher.find()) { |
| 62 | var start = matcher.start(1); | |
| 63 | var end = matcher.end(1); | |
| 64 | var placeholder = matcher.group(2); | |
| 65 | var newContent = insertSmartTag(element, paragraph, placeholder, start, end); | |
| 66 | var content = paragraph.getContent(); | |
| 67 |
1
1. process : removed call to java/util/List::clear → KILLED |
content.clear(); |
| 68 | content.addAll(newContent); | |
| 69 | string = asString(paragraph); | |
| 70 | matcher = pattern.matcher(string); | |
| 71 | } | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | /// A [TraversalUtilVisitor] implementation that collects paragraphs matching a given pattern. | |
| 76 | /// | |
| 77 | /// This class is used to traverse a document and collect all paragraph elements ([P]) that match a specified | |
| 78 | /// regular expression pattern. The collected paragraphs can be retrieved using the [#paragraphs()] method. | |
| 79 | public static class ParagraphCollector | |
| 80 | extends TraversalUtilVisitor<P> { | |
| 81 | ||
| 82 | private final Pattern pattern; | |
| 83 | private final List<P> results = new ArrayList<>(); | |
| 84 | ||
| 85 | ||
| 86 | /// Constructs a new [ParagraphCollector] with the specified pattern. | |
| 87 | /// | |
| 88 | /// @param pattern the regular expression pattern to match against paragraphs | |
| 89 | public ParagraphCollector(Pattern pattern) { | |
| 90 | this.pattern = pattern; | |
| 91 | } | |
| 92 | ||
| 93 | @Override | |
| 94 | public void apply(P element) { | |
| 95 | var matcher = pattern.asPredicate(); | |
| 96 | var string = asString(element); | |
| 97 |
1
1. apply : negated conditional → KILLED |
if (matcher.test(string)) { |
| 98 | results.add(element); | |
| 99 | } | |
| 100 | } | |
| 101 | ||
| 102 | /// Returns the list of collected paragraphs that matched the pattern. | |
| 103 | /// | |
| 104 | /// @return an unmodifiable list of paragraphs matching the specified pattern | |
| 105 | public List<P> paragraphs() { | |
| 106 |
1
1. paragraphs : replaced return value with Collections.emptyList for pro/verron/officestamper/api/PlaceholderHooker$ParagraphCollector::paragraphs → KILLED |
return results; |
| 107 | } | |
| 108 | } | |
| 109 | } | |
Mutations | ||
| 56 |
1.1 |
|
| 61 |
1.1 |
|
| 67 |
1.1 |
|
| 97 |
1.1 |
|
| 106 |
1.1 |