@Override
   public String getValue(EvaluationContext context) {
      // Use variable name if we just provide this.
      if (variableName != null && variable == null) {
         variable = context.lookupVariable(variableName);
         return (variable != null ? variable.toString() : "");
      }

      String propertyName = pathExpression;
      String propertyPath = null;
      int delimiterIndex = -1;

      // Search for a delimiter to isolate property name.
      for (String delimiter : PROPERTY_NAME_DELIMITERS) {
         delimiterIndex = pathExpression.indexOf(delimiter);
         if (delimiterIndex != -1) {
            propertyName = pathExpression.substring(0, delimiterIndex);
            propertyPath = pathExpression.substring(delimiterIndex);
            break;
         }
      }
      Object variableValue = getProperty(variable, propertyName);

      if (log.isDebugEnabled()) {
         log.debug("propertyName: {}", propertyName);
         log.debug("propertyPath: {}", propertyPath);
         log.debug("variableValue: {}", variableValue);
      }

      if (propertyPath != null) {
         if (variableValue.getClass().equals(String.class)) {
            if (propertyPath.startsWith("/")) {
               // This is a JSON Pointer or XPath expression to apply.
               String variableString = String.valueOf(variableValue);

               if (variableString.trim().startsWith("{") || variableString.trim().startsWith("[")) {
                  variableValue = getJsonPointerValue(variableString, propertyPath);
               } else if (variableString.trim().startsWith("<")) {
                  variableValue = getXPathValue(variableString, propertyPath);
               } else {
                  log.warn("Got a path query expression but content seems not to be JSON nor XML...");
                  variableValue = null;
               }
            }
         } else if (variableValue.getClass().isArray()) {
            if (propertyPath.matches(ARRAY_INDEX_REGEXP)) {
               Matcher m = ARRAY_INDEX_PATTERN.matcher(propertyPath);
               if (m.matches()) {
                  String arrayIndex = m.group(1);
                  Object[] variableValues = (Object[]) variableValue;
                  try {
                     variableValue = variableValues[Integer.parseInt(arrayIndex)];
                  } catch (ArrayIndexOutOfBoundsException ae) {
                     log.warn("Expression asked for " + arrayIndex + " but array is smaller (" + variableValues.length
                           + "). Returning null.");
                     variableValue = null;
                  }
               }
            }
         } else if (Map.class.isAssignableFrom(variableValue.getClass())) {
            if (propertyPath.matches(MAP_INDEX_REGEXP)) {
               Matcher m = MAP_INDEX_PATTERN.matcher(propertyPath);
               if (m.matches()) {
                  String mapKey = m.group(1);
                  Map variableValues = (Map) variableValue;
                  variableValue = variableValues.get(mapKey);
               }
            }
         }
      }

      return String.valueOf(variableValue);
   }
@Test
   void testXPathValue() {
      String xmlString = "<library>\n" + "  <name>My Personal Library</name>\n" + "  <books>\n"
            + "    <book><title>Title 1</title><author>Jane Doe</author></book>\n"
            + "    <book><title>Title 2</title><author>John Doe</author></book>\n" + "  </books>\n" + "</library>";
      EvaluableRequest request = new EvaluableRequest(xmlString, null);

      // Create new expression evaluating XML XPath.
      VariableReferenceExpression exp = new VariableReferenceExpression(request, "body/library/books/book[1]/author");
      String result = exp.getValue(new EvaluationContext());
      assertEquals("Jane Doe", result);
   }