s9e/sweetdom
SweetDOM is a lightweight PHP library for fast DOM parsing and manipulation. It offers a simple, jQuery-like API to find, traverse, and edit HTML/XML documents, making common scraping and transformation tasks easier without heavy dependencies.
Installation
composer require s9e/sweetdom
Add to compser.json if using a monorepo or custom setup.
First Use Case: DOM Manipulation
use S9e\SweetDom\SweetDom;
$dom = SweetDom::load('<div id="root"><p>Hello</p></div>');
$dom->find('p')->setText('World'); // Replace text
echo $dom->saveHtml();
// Output: <div id="root"><p>World</p></div>
Key Entry Points
SweetDom::load() – Parse HTML/XML string.SweetDom::loadFile() – Parse from a file.SweetDom::loadUrl() – Fetch and parse from a URL (with Guzzle dependency).Where to Look First
src/S9e/SweetDom/SweetDom.php for core methods.tests/ for usage examples and edge cases.XSLT-like Template Manipulation
$dom = SweetDom::load('<template><div class="item"><xsl:value-of select="@id"/></div></template>');
$dom->transform('<items><item id="123"/></items>');
// Renders: <div class="item">123</div>
Dynamic Content Injection
$dom = SweetDom::load('<div class="user"><xsl:attribute name="data-id"><xsl:value-of select="@id"/></xsl:attribute></div>');
$dom->transform('<user id="456" name="John"/>');
// Renders: <div class="user" data-id="456">John</div>
Laravel Blade Integration
// In a Blade view
$dom = SweetDom::load('<div><xsl:apply-templates select="*"/></div>');
$dom->transform(view('partials.content')->render());
echo $dom->saveHtml();
Batch Processing
$dom = SweetDom::load('<div><xsl:for-each select="//item"><xsl:copy-of select="."/></xsl:for-each></div>');
$dom->transform('<items><item>1</item><item>2</item></items>');
// Renders: <div><item>1</item><item>2</item></div>
Laravel Service Provider
Bind SweetDom to the container for dependency injection:
$this->app->singleton(SweetDom::class, function () {
return new SweetDom();
});
Caching Transformed Output Use Laravel’s cache to store transformed DOM results:
$cacheKey = 'transformed_'.$inputHash;
return Cache::remember($cacheKey, now()->addHours(1), function () use ($dom, $input) {
return $dom->transform($input)->saveHtml();
});
Error Handling Wrap transformations in try-catch:
try {
$result = $dom->transform($xml)->saveHtml();
} catch (\S9e\SweetDom\Exception $e) {
Log::error('SweetDom transform failed: '.$e->getMessage());
return back()->withErrors(['transform' => 'Invalid template']);
}
XSLT 1.0 Limitations
fn:substring-after).str_replace() or preg_replace() in PHP before/after transformation.Namespace Handling
$dom->setDefaultNamespace('http://example.com/ns');
Performance with Large Documents
//*[count(.//*) > 100]). Use //tagname or ./tagname where possible.HTML vs. XML Quirks
<img/>) may render differently in HTML vs. XML mode. Use SweetDom::loadHtml() or SweetDom::loadXml() explicitly.Enable Error Reporting
SweetDom::setErrorReporting(E_ALL);
Or configure via constructor:
$dom = new SweetDom(['error_reporting' => E_ALL]);
Inspect Intermediate States
Use saveHtml() or saveXml() to debug partial transformations:
$dom->find('//target')->setText('debug');
dd($dom->saveHtml()); // Dump and exit
XPath Validation Test XPath queries in a browser’s DevTools (Chrome/Firefox) or use XPath Tester before integrating into SweetDom.
Custom Functions Register PHP functions for use in XPath:
SweetDom::registerFunction('my:concat', function ($ctx, $args) {
return implode('', $args);
});
Usage in template:
<xsl:value-of select="my:concat(@prefix, ' ', @suffix)"/>
Event Listeners Extend core behavior via events (if supported in future versions). Currently, use method chaining:
$dom->find('//element')->each(function ($node) {
// Custom logic per node
});
Output Filtering
Post-process output with Laravel’s Str or Html helpers:
$html = $dom->saveHtml();
$cleaned = Str::of($html)->replace(['<script>', '</script>'], '');
Configuration Overrides Override default settings via constructor:
$dom = new SweetDom([
'error_reporting' => E_ALL,
'default_namespace' => 'http://ns.example.com',
'html_mode' => true,
]);
How can I help you explore Laravel packages today?