blob: da7e66957b2900b58ef695f7fcedf2b9bdf15b3a [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2019 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.converters.common.xpath.utils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jdom2.Document;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BulkXpathOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(BulkXpathOperation.class);
/**
* This method takes Xml Document object and the list of Xpath Strings as input-> and returns a Map with key as
* Xpath and Value as the List<Element> JDOM elements
*
* @param document
* @param xpaths
* @return Map - containing Key as Xpath and Value as the List of JDOM Element's
*/
public Map<String, List<Element>> invokeXpath(final Document document, final Collection<String> xpaths) {
final Map<String, List<Element>> resultsMap = new HashMap<>();
try {
// building optimized map
final Map<String, XpathFragment> fragmentsMap = new HashMap<>();
for (final String xpath : xpaths) {
/*-example Xpath : //osModel/scheduler[3] */
/*- this buffer is used to populate characters of xpath fragment string till the first occurance of "/" */
final StringBuilder fragmentStringBuffer = new StringBuilder();
final char[] charArray = xpath.toCharArray();
final int length = charArray.length;
XpathFragment parentFragmentObject = null;
for (int i = 0; i < length; i++) {
final char _char = charArray[i];
/*- on occurance of "/" char, then the next character is also checked if it is "/" */
if (_char == '/') {
if ((i + 1) < length) {
final char _char_next = charArray[i + 1];
if (_char_next == '/') {
fragmentStringBuffer.append(_char);
fragmentStringBuffer.append(_char_next);
i++;
}
/*- on occurance of "/" char, then the next character is also checked if it is "/"
* Below is the case where next char is not "/"
* */
else {
/*- containing only parts of the fragment */
final String fragmentString = fragmentStringBuffer.toString();
/*- example :
*
* - First iteration : //osModel
* - Second iteration :
* */
if (fragmentString.length() > 0) {
/*- this the content of Xpath string from the begining till the current character (i.e. index of i)*/
final String xpathSubContent_from_begining_till_current_index = xpath.substring(0,
i);
if (fragmentsMap.containsKey(xpathSubContent_from_begining_till_current_index)) {
parentFragmentObject = fragmentsMap
.get(xpathSubContent_from_begining_till_current_index);
}
else {
final XpathFragment fragmentObject = new XpathFragment();
fragmentObject.setValue(fragmentString);
fragmentObject.setParent(parentFragmentObject);
/*-updating map*/
fragmentsMap.put(xpathSubContent_from_begining_till_current_index,
fragmentObject);
/*- marking the current fragment as parent fragment for the next iteration */
parentFragmentObject = fragmentObject;
}
}
fragmentStringBuffer.setLength(0);
fragmentStringBuffer.append("./");
}
}
}
else {
fragmentStringBuffer.append(_char);
}
}
/*- setting last fragment value, as it will not set in the previous loop */
final String fragmentString = fragmentStringBuffer.toString();
if (fragmentString.length() > 0) {
final XpathFragment fragment = new XpathFragment();
fragment.setValue(fragmentString);
fragment.setParent(parentFragmentObject);
/*-updating map*/
fragmentsMap.put(xpath, fragment);
}
}
/*- Printing the contents of FragmentsMap */
final Set<String> keySet = fragmentsMap.keySet();
for (final String string : keySet) {
LOGGER.trace("Xpath Fragment : {} associated Xpath chunk : {}", string, fragmentsMap.get(string).getValue());
}
/*- execute Xpath evaluation */
final Element rootElement = document.getRootElement();
for (final String xpath : xpaths) {
if (!resultsMap.containsKey(xpath)) {
final XpathFragment xpathFragment = fragmentsMap.get(xpath);
if (xpathFragment != null) {
xpathFragment.visit(rootElement);
final List<Element> xmlElements = xpathFragment.getXmlElements();
resultsMap.put(xpath, xmlElements);
LOGGER.trace("xpath : {} elements : {}", xpath, xmlElements.size());
}
}
}
}
catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
throw e;
}
return resultsMap;
}
}