View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
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   * @author Frank L\u00FCtzenkirchen
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 }