void (@NotNull final String id, @NotNull final XmlAttributeValue attributeValue, final boolean soft) { List<Pair<XmlAttributeValue, Boolean>> list = myId2AttributeListMap.get(id); if (list == null) { list = new ArrayList<>(); myId2AttributeListMap.put(id, list); } else if (!soft) { final boolean html = HtmlUtil.isHtmlFile(attributeValue); final boolean html5 = HtmlUtil.isHtml5Context(attributeValue); // mark as duplicate List<XmlAttributeValue> notSoft = ContainerUtil.mapNotNull(list, (NullableFunction<Pair<XmlAttributeValue, Boolean>, XmlAttributeValue>)pair -> { if (html5 && !"id".equalsIgnoreCase(((XmlAttribute)pair.first.getParent()).getName())) { // according to HTML 5 (http://www.w3.org/TR/html5/dom.html#the-id-attribute) spec // only id attribute is unique identifier return null; } if (html && pair.first.getParent().getParent() == attributeValue.getParent().getParent()) { // according to HTML 4 (http://www.w3.org/TR/html401/struct/global.html#adef-id, // http://www.w3.org/TR/html401/struct/links.html#h-12.2.3) spec id and name occupy // same namespace, but having same values on one tag is ok return null; } return pair.second ? null : pair.first; }); if (!notSoft.isEmpty()) { myPossiblyDuplicateIds.addAll(notSoft); myPossiblyDuplicateIds.add(attributeValue); } } list.add(new Pair<>(attributeValue, soft)); }