Use DOM and XPath to make some changes in HTML document
Your code seems to globally do the right job, using a right way, and I can't see how you could really improve performance.
I only noticed a few bad points:


Unless I missed some subtleness, there is a typo in the case 'append': branch: it should be using $xpath_results-&gt;**parentNode**,like others.
You didn't take in account a possible error condition at $newNode-&gt;appendXML($replacement);: it may return FALSE, so you should cancel the process in that case.
The same applies to a possible wrong value in the task index of a pattern: it should be taken in account through the default: option of the switch().


In the other hand I would suggest some improvements at the coding level itself, essentially for readability.


You're using foreach ($patterns as $key =&gt; $value), but then always write $patterns[$key][...] so you force PHP to a few more work, while $value is never used.
I suggest to rather use foreach ($patterns as $value), then $value[...].
(or even more readable foreach ($patterns as $pattern), then $pattern[...])
Still for readability I would add a separate variable to clearly distinguish the successive "avatars" of $xpath_results, which is first a DOMNodeList then a DOMNode.
So you could change your DOMNode extraction to $node = $xpath_results-&gt;item(0);, and all following code becomes much more obvious.
Your // Assing some valuespart could be reduced to the $node assignation above: the two other variables are only used once so you could merely write $newNode-&gt;appendXML($pattern['insert']); and switch ($pattern['task']).


So here is my suggestion for the whole snippet after the remarks above:

if ($html) {
    $dom = new DOMDocument();
    if (!$dom-&gt;loadHTML($html)) {
        $error = 'Error while loading source HTML!';
    } else {
        $dom-&gt;formatOutput = true;
        // Use DomXPath
        $xpath = new DomXPath($dom);
        // Process Dom changes
        foreach ($patterns as $pattern) {
            $xpath_results = $xpath-&gt;query($pattern['xpath']);
            if ($xpath_results-&gt;length) {
                $node = $xpath_results-&gt;item(0);

                if ($task != 'remove') {
                    // Create the replacement
                    $newNode = $dom-&gt;createDocumentFragment();
                    if (!$newNode-&gt;appendXML($pattern['insert'])) {
                        $error = "Wrong insert pattern: $pattern['insert']!";
                        break;
                    }
                }
                if (!@$error) {
                    switch ($pattern['task']) {
                        case 'remove':
                            $node-&gt;parentNode-&gt;removeChild($node);
                            break;
                        case 'replace':
                            $node-&gt;parentNode-&gt;replaceChild($newNode, $node);
                            break;
                        case 'append':
                            $node-&gt;parentNode-&gt;appendChild($newNode);
                            break;
                        case 'prepend':
                            $node-&gt;parentNode-&gt;insertBefore($newNode, $node);
                            break;
                        default:
                            $error = "Wrong task pattern: $pattern['task']!";
                    }
                }
            }
        }
    }
    if (@$error) {
        // print or return $error...
    } else {
        // Save Dom
        $html = $dom-&gt;saveXML($dom-&gt;documentElement);
    }
}


For the error processing, I arbitrarily choosed one simple option among numerous different possiilities.  You can notice:


The @$error form: it is a simple and clear way to allow using variables set only in certain cases without having defined them previously.
Still for readability, I changed the initial tests into more simple (and sufficient) forms: if ($html) and if (!dom-&gt;loadHTML($html)).