24hoursmedia/php-dom-manipulations
Lightweight PHP helpers for manipulating HTML DOM documents. Create, find, update, replace, and remove nodes and attributes with a simple API suited for scraping, templating, and HTML cleanup tasks in legacy or modern PHP projects.
Installation:
composer require 24hoursmedia/php-dom-manipulations
Add to composer.json if not auto-loaded:
"autoload": {
"psr-4": {
"App\\": "app/",
"24HoursMedia\\DomManipulations\\": "vendor/24hoursmedia/php-dom-manipulations/src/"
}
}
Run composer dump-autoload.
First Use Case: Load a DOMDocument and apply a manipulation:
use DomManipulations\DomManipulations;
$dom = new \DOMDocument();
$dom->loadHTML('<div id="content"><p>Hello</p><p>World</p></div>');
$manipulator = new DomManipulations($dom);
$manipulator->removeElementsByTagName('p'); // Removes all `<p>` tags
echo $dom->saveHTML();
Key Entry Points:
DomManipulations class (main facade for DOM operations).removeElementsByTagName(), addClass(), removeClass(), setAttribute(), etc.Scraping & Cleaning HTML:
$dom = new \DOMDocument();
$dom->loadHTML($rawHtml);
$manipulator = new DomManipulations($dom);
// Remove unwanted elements (e.g., scripts, ads)
$manipulator->removeElementsByTagName(['script', 'iframe', 'noscript']);
// Normalize classes (e.g., add/remove prefixes)
$manipulator->addClass('content *', 'normalized-class');
Dynamic Attribute Manipulation:
// Batch update attributes
$manipulator->setAttribute('a[href]', 'target', '_blank');
$manipulator->removeAttribute('div[data-tracking]', 'data-tracking');
// Conditional logic (e.g., only update specific links)
$links = $dom->getElementsByTagName('a');
foreach ($links as $link) {
if (strpos($link->getAttribute('href'), 'external.com') !== false) {
$manipulator->addClass($link, 'external-link');
}
}
Integration with Laravel:
$cleanedHtml = $manipulator->process($rawHtml);
return view('template', ['content' => $cleanedHtml]);
$this->app->bind(DomManipulations::class, function ($app) {
$dom = new \DOMDocument();
return new DomManipulations($dom);
});
Batch Processing:
$dom = new \DOMDocument();
$dom->loadHTML($html);
$manipulator = new DomManipulations($dom);
$manipulator->batch([
'remove' => ['.old-class', '#legacy-id'],
'add' => ['.new-class', 'body', 'global-style'],
]);
$nodes = collect($dom->getElementsByTagName('div'));
$nodes->each(function ($node) {
$manipulator->setAttribute($node, 'data-processed', 'true');
});
$html = file_get_html('https://example.com');
$dom = new \DOMDocument();
$dom->loadHTML($html->save());
$manipulator = new DomManipulations($dom);
// Clean up...
DOMDocument Quirks:
DOMDocument, which can be finicky with malformed HTML. Always validate input:
@$dom->loadHTML($html); // Suppress warnings for broken HTML
loadHTML() instead of load() for HTML strings to avoid strict XML parsing.Selector Limitations:
:nth-child may not work. Test thoroughly:
// Works: remove all <p> tags
$manipulator->removeElementsByTagName('p');
// May fail: remove every other <tr>
$manipulator->removeElementsBySelector('tr:nth-of-type(even)');
Attribute Conflicts:
setAttribute() will overwrite existing values. Use toggleAttribute() for conditional logic:
$manipulator->toggleAttribute('input[type="checkbox"]', 'disabled', true);
Memory Usage:
DOMXPath for targeted queries.echo $dom->saveHTML(); // Full output
echo $dom->saveHTML($node); // Inspect a specific node
libxml_use_internal_errors(true);
$dom->loadHTML($html);
$errors = libxml_get_errors();
// Handle errors...
Custom Selectors: Extend the package by adding selector logic (e.g., regex-based matching):
$manipulator->customRemove(function ($node) {
return preg_match('/unwanted-text/', $node->nodeValue);
});
Event Hooks:
Intercept DOM manipulations by subclassing DomManipulations:
class CustomDomManipulations extends DomManipulations {
public function removeElementsByTagName($tagName) {
// Pre-processing logic
parent::removeElementsByTagName($tagName);
// Post-processing logic
}
}
Laravel Service Provider: Bind a configured instance:
$this->app->singleton(DomManipulations::class, function ($app) {
$dom = new \DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->substituteEntities = true;
return new DomManipulations($dom);
});
$dom = new \DOMDocument();
$manipulator = new DomManipulations($dom);
// Reuse $manipulator for multiple operations
DOMXPath for better performance:
$xpath = new \DOMXPath($dom);
$nodes = $xpath->query('//div[contains(@class, "sidebar")]');
How can I help you explore Laravel packages today?