Nick is correct that this can/should be done with DomDocument.
Also worth mentioning is a buggy side-effect when adding curly braces to the attribute strings (they get encoded) when using saveHTML()
to access the mutated document. To workaround this, use saveXML()
and just trim away the xml tag that is prepended to the document.
I am wrapping your sample tags in a parent tag so that DomDocument can function normally and not mangle your document structure. This might be an unnecessary precaution for your project.
My snippet directly targets the qualifying attributes using XPath and replaces their values without any regex. The pipe (|
) in my xpath expression means "or" -- so it targets the img tags' src attribute OR the link tags' href attribute.
Code: (Demo)
$html = <<<HTML
<div>
<img src="icons/example.svg">
<a href="http://www.example.com">a link</a>
<link href="css/example.css">
<iframe src="http://www.example.com/default.htm"></iframe>
</div>
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach ($xpath->query('//img/@src | //link/@href') as $attr) {
$attr->value = "{{asset('" . $attr->value . "')}}";
}
echo substr($dom->saveXML(), 38); // remove the auto-generated xml tag from the start
Output:
<div>
<img src="{{asset('icons/example.svg')}}"/>
<a href="http://www.example.com">a link</a>
<link href="{{asset('css/example.css')}}"/>
<iframe src="http://www.example.com/default.htm"/>
</div>
Whoops, I just saw the last request in your question.
The implementation of not()
and starts-with()
are applied to both tags to disqualify elements that are already converted to mustache code.
New xpath expression: (Demo)
//img[not(starts-with(@src,"{{asset"))]/@src | //link[not(starts-with(@href,"{{asset"))]/@href