1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.common.xml;
20
21 import java.net.URLEncoder;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.jdom2.Parent;
32 import org.jdom2.filter.Filters;
33 import org.jdom2.xpath.XPathExpression;
34 import org.jdom2.xpath.XPathFactory;
35 import org.mycore.common.MCRConstants;
36 import org.mycore.common.config.MCRConfiguration2;
37
38
39
40
41 public class MCRXPathEvaluator {
42
43 private static final Logger LOGGER = LogManager.getLogger(MCRXPathEvaluator.class);
44
45 private static final Pattern PATTERN_XPATH = Pattern.compile("\\{([^\\}]+)\\}");
46
47 private static final XPathFactory XPATH_FACTORY = MCRConfiguration2.getString("MCR.XPathFactory.Class")
48 .map(XPathFactory::newInstance)
49 .orElseGet(XPathFactory::instance);
50
51 private Map<String, Object> variables;
52
53 private List<Object> context;
54
55 public MCRXPathEvaluator(Map<String, Object> variables, List<Object> context) {
56 this.variables = variables;
57 this.context = context;
58 }
59
60 public MCRXPathEvaluator(Map<String, Object> variables, Parent context) {
61 this.variables = variables;
62 this.context = new ArrayList<>();
63 this.context.add(context);
64 }
65
66 public String replaceXPaths(String text, boolean urlEncode) {
67 Matcher m = PATTERN_XPATH.matcher(text);
68 StringBuffer sb = new StringBuffer();
69 while (m.find()) {
70 String replacement = replaceXPathOrI18n(m.group(1));
71 if (urlEncode) {
72 replacement = URLEncoder.encode(replacement, StandardCharsets.UTF_8);
73 }
74 m.appendReplacement(sb, replacement);
75 }
76 m.appendTail(sb);
77 return sb.toString();
78 }
79
80 public String replaceXPathOrI18n(String expression) {
81 expression = migrateLegacyI18nSyntaxToExtensionFunction(expression);
82 return evaluateXPath(expression);
83 }
84
85 private String migrateLegacyI18nSyntaxToExtensionFunction(String expression) {
86 if (expression.startsWith("i18n:")) {
87 expression = expression.substring(5);
88 if (expression.contains(",")) {
89 int pos = expression.indexOf(",");
90 String key = expression.substring(0, pos);
91 String xPath = expression.substring(pos + 1);
92 expression = "i18n:translate('" + key + "'," + xPath + ")";
93 } else {
94 expression = "i18n:translate('" + expression + "')";
95 }
96 }
97 return expression;
98 }
99
100 public String evaluateXPath(String xPathExpression) {
101 xPathExpression = "string(" + xPathExpression + ")";
102 Object result = evaluateFirst(xPathExpression);
103 return result == null ? "" : (String) result;
104 }
105
106 public boolean test(String xPathExpression) {
107 Object result = evaluateFirst(xPathExpression);
108 if (result == null) {
109 return false;
110 } else if (result instanceof Boolean) {
111 return (Boolean) result;
112 } else {
113 return true;
114 }
115 }
116
117 public Object evaluateFirst(String xPathExpression) {
118 try {
119 XPathExpression<Object> xPath = XPATH_FACTORY.compile(xPathExpression, Filters.fpassthrough(), variables,
120 MCRConstants.getStandardNamespaces());
121 return xPath.evaluateFirst(context);
122 } catch (Exception ex) {
123 LOGGER.warn("unable to evaluate XPath: {}", xPathExpression);
124 LOGGER.warn("XPath factory used is {} {}", XPATH_FACTORY.getClass().getCanonicalName(),
125 MCRConfiguration2.getString("MCR.XPathFactory.Class").orElse(null));
126 LOGGER.warn(ex);
127 return null;
128 }
129 }
130
131 }