- $old = str_replace('"', '', $old);
- $matchingLinks = $xpath->query('//body//*//*[@href="' . $old . '"]');
- foreach ($matchingLinks as $domElem) {
- $domElem->setAttribute('href', $new);
+ /* @var DOMNode $child */
+ foreach ($element->childNodes as $child) {
+ if ($child instanceof DOMElement && ($depth === 0 || in_array($child->nodeName, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']) || $child->getAttribute('id'))) {
+ [$oldId, $newId] = $this->setUniqueId($child, $idMap);
+ if ($newId && $newId !== $oldId && !isset($idMap[$oldId])) {
+ $changeMap[$oldId] = $newId;
+ }
+ }
+
+ if ($child->hasChildNodes()) {
+ $this->updateIdsRecursively($child, $depth + 1, $idMap, $changeMap);
+ }
+ }
+ }
+
+ /**
+ * Update the all links in the given xpath to apply requires changes within the
+ * given $changeMap array.
+ */
+ protected function updateLinks(DOMXPath $xpath, array $changeMap): void
+ {
+ if (empty($changeMap)) {
+ return;
+ }
+
+ $links = $xpath->query('//body//*//*[@href]');
+ /** @var DOMElement $domElem */
+ foreach ($links as $domElem) {
+ $href = ltrim($domElem->getAttribute('href'), '#');
+ $newHref = $changeMap[$href] ?? null;
+ if ($newHref) {
+ $domElem->setAttribute('href', '#' . $newHref);
+ }