diff --git a/misc/config_tools/scenario_config/elementpath_overlay.py b/misc/config_tools/scenario_config/elementpath_overlay.py
index d773bf587..5178db3bd 100644
--- a/misc/config_tools/scenario_config/elementpath_overlay.py
+++ b/misc/config_tools/scenario_config/elementpath_overlay.py
@@ -16,7 +16,10 @@ BaseParser = elementpath.XPath2Parser
class CustomParser(BaseParser):
SYMBOLS = BaseParser.SYMBOLS | {
# Bit-wise operations
- 'bitwise-and'
+ 'bitwise-and',
+
+ 'has',
+ 'duplicate-values',
}
method = CustomParser.method
@@ -53,6 +56,34 @@ def evaluate(self, context=None):
return aux(OPERATORS_MAP[self.symbol])
+@method(function('has', nargs=2))
+def evaluate_has_function(self, context=None):
+ arg2 = self.get_argument(context, index=1, cls=str)
+ for item in self[0].select(context):
+ value = self.data_value(item)
+ if value == arg2:
+ return True
+ return False
+
+@method(function('duplicate-values', nargs=1))
+def select_duplicate_values_function(self, context=None):
+ def duplicate_values():
+ results = []
+ reported = []
+ for item in self[0].select(context):
+ value = self.data_value(item)
+ if context is not None:
+ context.item = value
+
+ if value in results:
+ if value not in reported:
+ yield value
+ reported.append(value)
+ else:
+ results.append(value)
+
+ yield from duplicate_values()
+
###
# Collection of counter examples
diff --git a/misc/config_tools/scenario_config/validator.py b/misc/config_tools/scenario_config/validator.py
index 9441287da..b1f479f8c 100755
--- a/misc/config_tools/scenario_config/validator.py
+++ b/misc/config_tools/scenario_config/validator.py
@@ -101,7 +101,7 @@ class ScenarioValidator:
@staticmethod
def format_paths(unified_node, parent_map, report_on, variables):
- elems = elementpath.select(unified_node, report_on, variables = variables)
+ elems = elementpath.select(unified_node, report_on, variables = variables, parser = elementpath.XPath2Parser)
paths = []
for elem in elems:
path = []
@@ -156,7 +156,7 @@ class ScenarioValidator:
expr_regex = re.compile("{[^{}]*}")
exprs = set(expr_regex.findall(description))
for expr in exprs:
- result = elementpath.select(unified_node, expr.strip("{}"), variables = variables)
+ result = elementpath.select(unified_node, expr.strip("{}"), variables = variables, parser = elementpath.XPath2Parser)
if isinstance(result, list):
if len(result) == 1:
value = format_node(result[0])
diff --git a/misc/config_tools/schema/datachecks.xsd b/misc/config_tools/schema/datachecks.xsd
index 14222497a..f8c934eda 100644
--- a/misc/config_tools/schema/datachecks.xsd
+++ b/misc/config_tools/schema/datachecks.xsd
@@ -11,6 +11,7 @@
+