+ private static void removeExistingListElements(
+ final Collection<FragmentEntity> fragmentEntities,
+ final Map<String, FragmentEntity> existingListElementFragmentEntitiesByXPath) {
+ fragmentEntities.removeAll(existingListElementFragmentEntitiesByXPath.values());
+ }
+
+ private static String getListNodeXpathPrefix(final Collection<DataNode> replacementDataNodes) {
+ final String firstChildNodeXpath = replacementDataNodes.iterator().next().getXpath();
+ return firstChildNodeXpath.substring(0, firstChildNodeXpath.lastIndexOf("[") + 1);
+ }
+
+ private static FragmentEntity getFragmentForReplacement(final FragmentEntity parentEntity,
+ final DataNode replacementDataNode,
+ final FragmentEntity existingListNodeElementEntity) {
+ if (existingListNodeElementEntity == null) {
+ return convertToFragmentWithAllDescendants(
+ parentEntity.getDataspace(), parentEntity.getAnchor(), replacementDataNode);
+ }
+ if (replacementDataNode.getChildDataNodes().isEmpty()) {
+ copyAttributesFromReplacementDataNode(existingListNodeElementEntity, replacementDataNode);
+ existingListNodeElementEntity.getChildFragments().clear();
+ } else {
+ replaceDataNodeTree(existingListNodeElementEntity, replacementDataNode);
+ }
+ return existingListNodeElementEntity;
+ }
+
+ private static boolean isNewDataNode(final DataNode replacementDataNode,
+ final Map<String, FragmentEntity> existingListNodeElementsByXpath) {
+ return !existingListNodeElementsByXpath.containsKey(replacementDataNode.getXpath());
+ }
+
+ private static void copyAttributesFromReplacementDataNode(final FragmentEntity existingListNodeElementEntity,
+ final DataNode replacementDataNode) {
+ final FragmentEntity replacementFragmentEntity =
+ FragmentEntity.builder().attributes(GSON.toJson(replacementDataNode.getLeaves())).build();
+ existingListNodeElementEntity.setAttributes(replacementFragmentEntity.getAttributes());
+ }
+
+ private static Map<String, FragmentEntity> extractListElementFragmentEntitiesByXPath(
+ final Set<FragmentEntity> childEntities, final String listNodeXpathPrefix) {
+ return childEntities.stream()
+ .filter(fragmentEntity -> fragmentEntity.getXpath().startsWith(listNodeXpathPrefix))
+ .collect(Collectors.toMap(FragmentEntity::getXpath, fragmentEntity -> fragmentEntity));
+ }
+
+ @Override
+ @Transactional
+ public void deleteListDataNodes(final String dataspaceName, final String anchorName, final String listNodeXpath) {
+ final String parentNodeXpath = listNodeXpath.substring(0, listNodeXpath.lastIndexOf('/'));
+ final FragmentEntity parentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
+ final String descendantNode = listNodeXpath.substring(listNodeXpath.lastIndexOf('/'));
+ final Matcher descendantNodeHasListNodeKey = Pattern.compile(REG_EX_FOR_LIST_NODE_KEY).matcher(descendantNode);
+
+ final boolean xpathPointsToAValidChildNodeWithKey = parentEntity.getChildFragments().stream().anyMatch(
+ fragment -> fragment.getXpath().equals(listNodeXpath));
+
+ final boolean xpathPointsToAValidChildNodeWithoutKey = parentEntity.getChildFragments().stream().anyMatch(
+ fragment -> fragment.getXpath().replaceAll(REG_EX_FOR_LIST_NODE_KEY, "").equals(listNodeXpath));
+
+ if ((descendantNodeHasListNodeKey.find() && xpathPointsToAValidChildNodeWithKey)
+ ||
+ (!descendantNodeHasListNodeKey.find() && xpathPointsToAValidChildNodeWithoutKey)) {
+ removeListNodeDescendants(parentEntity, listNodeXpath);
+ } else {
+ throw new DataNodeNotFoundException(parentEntity.getDataspace().getName(),
+ parentEntity.getAnchor().getName(), listNodeXpath);
+ }
+ }
+