package org.exist.util; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Utility class for extracting parameters from * DOM representation into a Map * * * @author Adam Retter <adam@exist-db.org> */ public class ParametersExtractor { public final static String PARAMETERS_ELEMENT_NAME = "parameters"; public final static String PARAMETER_ELEMENT_NAME = "parameter"; private final static String PARAMETER_NAME_ATTRIBUTE = "name"; private final static String PARAMETER_VALUE_ATTRIBUTE = "value"; /** * @param parameters A "parameters" element, which may contain "parameter" child elements */ public static Map<String, List<? extends Object>> extract(final Element parameters) { final Map<String, List<? extends Object>> result; if(parameters == null || !parameters.getLocalName().equals(PARAMETERS_ELEMENT_NAME)) { result = new HashMap<>(0); } else { final String namespace = parameters.getNamespaceURI(); final NodeList nlParameter = parameters.getElementsByTagNameNS(namespace, PARAMETER_ELEMENT_NAME); result = extract(nlParameter); } return result; } /** * @param nlParameter A NodeList of "parameter" elements */ public static Map<String, List<? extends Object>> extract(final NodeList nlParameter) { final Map<String, List<? extends Object>> result; if(nlParameter == null || nlParameter.getLength() == 0) { result = new HashMap<>(0); } else { result = extractParameters(nlParameter); } return result; } private static Map<String, List<? extends Object>> extractParameters(final NodeList nlParameter) { final Map<String, List<?>> parameters = new HashMap<String, List<?>>(nlParameter.getLength()); for (int i = 0 ; i < nlParameter.getLength(); i++) { final Element param = (Element)nlParameter.item(i); //TODO : rely on schema-driven validation -pb final String name = param.getAttribute(PARAMETER_NAME_ATTRIBUTE); /*if(name == null) { throwOrLog("Expected attribute '" + PARAMETER_NAME_ATTRIBUTE + "' for element '" + PARAMETER_ELEMENT_NAME + "' in trigger's configuration.", testOnly); }*/ List values = parameters.get(name); final String value = param.getAttribute(PARAMETER_VALUE_ATTRIBUTE); if(value != null && value.length() > 0) { if(values == null) { values = new ArrayList<String>(); } values.add(value); } else { //are there child nodes? if(param.getChildNodes().getLength() > 0) { if(values == null) { values = new ArrayList<Map<String, List>>(); } values.add(getParameterChildParameters(param)); } } parameters.put(name, values); } return parameters; } private static Map<String, List> getParameterChildParameters(final Element parameter) { final Map<String, List> results = new HashMap<>(); final NodeList childParameters = parameter.getChildNodes(); for(int i = 0; i < childParameters.getLength(); i++) { final Node nChildParameter = childParameters.item(i); if(nChildParameter instanceof Element) { final Element childParameter = (Element)nChildParameter; final String name = childParameter.getLocalName(); if(childParameter.getAttributes().getLength() > 0){ List<Properties> childParameterProperties = (List<Properties>)results.get(name); if(childParameterProperties == null) { childParameterProperties = new ArrayList<>(); } final NamedNodeMap attrs = childParameter.getAttributes(); final Properties props = new Properties(); for(int a = 0; a < attrs.getLength(); a++) { final Node attr = attrs.item(a); props.put(attr.getLocalName(), attr.getNodeValue()); } childParameterProperties.add(props); results.put(name, childParameterProperties); } else { List<String> strings = (List<String>)results.get(name); if(strings == null) { strings = new ArrayList<>(); } strings.add(childParameter.getNodeValue()); results.put(name, strings); } } } return results; } /** * Parses a structure like <parameters><param name="a" value="1"/><param * name="b" value="2"/></parameters> into a set of Properties * * @param nParameters * The parameters Node * @return a set of name value properties for representing the XML * parameters */ public static Properties parseParameters(final Node nParameters){ return parseProperties(nParameters, "param"); } /** * Parses a structure like <properties><property name="a" value="1"/><property * name="b" value="2"/></properties> into a set of Properties * * @param nProperties * The properties Node * @return a set of name value properties for representing the XML * properties */ public static Properties parseProperties(final Node nProperties) { return parseProperties(nProperties, "property"); } /** * Parses a structure like <features><feature name="a" value="1"/><feature * name="b" value="2"/></features> into a set of Properties * * @param nFeatures * The features Node * @return a set of name value properties for representing the XML * features */ public static Properties parseFeatures(final Node nFeatures) { return parseProperties(nFeatures, "feature"); } /** * Parses a structure like <properties><property name="a" value="1"/><property * name="b" value="2"/></properties> into a set of Properties * * @param container * The container of the properties * @param elementName * The name of the property element * @return a set of name value properties for representing the XML * properties */ private static Properties parseProperties(final Node container, final String elementName) throws IllegalArgumentException { final Properties properties = new Properties(); if(container != null && container.getNodeType() == Node.ELEMENT_NODE) { final NodeList params = ((Element) container).getElementsByTagName(elementName); for(int i = 0; i < params.getLength(); i++) { final Element param = ((Element) params.item(i)); final String name = param.getAttribute("name"); final String value = param.getAttribute("value"); if(name != null && value != null) { properties.setProperty(name, value); } else { if(name == null) { throw new IllegalArgumentException("'name' attribute missing for " + elementName); } else { throw new IllegalArgumentException("'value' attribute missing for " + elementName); } } } } return properties; } }