/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.test.rest.json; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.test.rest.Stash; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Holds a json object and allows to extract specific values from it */ public class JsonPath { final String json; final Map<String, Object> jsonMap; public JsonPath(String json) throws IOException { this.json = json; this.jsonMap = convertToMap(json); } private static Map<String, Object> convertToMap(String json) throws IOException { try (XContentParser parser = JsonXContent.jsonXContent.createParser(json)) { return parser.mapOrdered(); } } /** * Returns the object corresponding to the provided path if present, null otherwise */ public Object evaluate(String path) { return evaluate(path, Stash.EMPTY); } /** * Returns the object corresponding to the provided path if present, null otherwise */ public Object evaluate(String path, Stash stash) { String[] parts = parsePath(path); Object object = jsonMap; for (String part : parts) { object = evaluate(part, object, stash); if (object == null) { return null; } } return object; } @SuppressWarnings("unchecked") private Object evaluate(String key, Object object, Stash stash) { if (stash.isStashedValue(key)) { key = stash.unstashValue(key).toString(); } if (object instanceof Map) { return ((Map<String, Object>) object).get(key); } if (object instanceof List) { List<Object> list = (List<Object>) object; try { return list.get(Integer.valueOf(key)); } catch (NumberFormatException e) { throw new IllegalArgumentException("element was a list, but [" + key + "] was not numeric", e); } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException("element was a list with " + list.size() + " elements, but [" + key + "] was out of bounds", e); } } throw new IllegalArgumentException("no object found for [" + key + "] within object of class [" + object.getClass() + "]"); } private String[] parsePath(String path) { List<String> list = new ArrayList<>(); StringBuilder current = new StringBuilder(); boolean escape = false; for (int i = 0; i < path.length(); i++) { char c = path.charAt(i); if (c == '\\') { escape = true; continue; } if (c == '.') { if (escape) { escape = false; } else { if (current.length() > 0) { list.add(current.toString()); current.setLength(0); } continue; } } current.append(c); } if (current.length() > 0) { list.add(current.toString()); } return list.toArray(new String[list.size()]); } }