LaravelPackages.net
Acme Inc.
Toggle sidebar
devoashim/regxdomdocument

Pure regex-based DOM manipulation library with React/JSX template literal support. No DOMDocument, no XML parsing - just regex magic!

3
0
1.0.3
About devoashim/regxdomdocument

devoashim/regxdomdocument is a Laravel package for pure regex-based dom manipulation library with react/jsx template literal support. no domdocument, no xml parsing - just regex magic!. It currently has 0 GitHub stars and 3 downloads on Packagist (latest version 1.0.3). Install it with composer require devoashim/regxdomdocument. Discover more Laravel packages by devoashim or browse all Laravel packages to compare alternatives.

Last updated

regxdomdocument - Complete Guide & Reference

Pure regex-based DOM manipulation library with React/JSX Template Literal Support. No DOMDocument, no XML parsing - just regex magic!

Perfect for preserving exact HTML structure, React/Vue components, and template variables.

Installation

composer require devoashim/regxdomdocument

Table of Contents


Quick Start

Basic HTML Manipulation

use devoashim\regxdomdocument\XDOM;

$dom = XDOM::load($html);

// Find and modify elements
$dom->find('#app')->setInnerHTML('<Component />');
$dom->find('.header')->addClass('active');

echo $dom->html();

Template Literal Generation

Convert static className to dynamic React template literal:

$dom = XDOM::loadFromFile('index.html');

// Convert static to dynamic
$dom->find('.stricky-header')
    ->setDynamicClass('isStick', 'stricky-fixed');

// Output HTML
echo $dom->html();

Before:

<div className="stricky-header stricked-menu main-menu">

After:

<div className={`stricky-header stricked-menu main-menu ${isStick ? 'stricky-fixed' : ''}`}>

Loading HTML

Returns: XDOM instance

// From string
$dom = XDOM::load($htmlString);

// From file
$dom = XDOM::loadFromFile('/path/to/file.html');

// From Laravel Storage
$path = Storage::disk('public')->path('index.html');
$dom = XDOM::loadFromFile($path);

Finding Elements

Returns: RegexNodeCollection

// By ID
$element = $dom->find('#header');
$element = $dom->find('#main-content');

// By Class
$elements = $dom->find('.container');
$elements = $dom->find('.nav-item');

// By Tag
$elements = $dom->find('div');
$elements = $dom->find('nav');
$elements = $dom->find('section');

// Combined Selectors
$element = $dom->find('div#main');        // Tag + ID
$element = $dom->find('section#about');

$elements = $dom->find('div.container');  // Tag + Class
$elements = $dom->find('nav.main-nav');

// Descendant (parent child)
$elements = $dom->find('header nav');
$elements = $dom->find('div .content');
$elements = $dom->find('main section');

Getting Content

String Returns

// Get inner HTML (content between tags)
$content = $dom->find('#app')->innerHTML();
// <div id="app">THIS CONTENT</div>
// Returns: "THIS CONTENT"

// Get outer HTML (full element with tags)
$html = $dom->find('#app')->outerHTML();
// Returns: "<div id="app">Content</div>"

// Get text content (strip all HTML)
$text = $dom->find('#app')->text();
// <div id="app"><p>Hello <b>World</b></p></div>
// Returns: "Hello World"

// Get complete HTML document
$fullHtml = $dom->html();

// Get attribute value
$value = $dom->find('#app')->attr('data-value');
$id = $dom->find('div')->attr('id');
$class = $dom->find('nav')->attr('class');

Array Returns

// Get first element
$first = $dom->find('.item')->first();
// Returns: ['html' => '...', 'position' => ..., 'tag' => '...']

// Get last element
$last = $dom->find('.item')->last();

// Get element by index
$third = $dom->find('.item')->get(2);  // 0-based index

// Get all matches as array
$matches = $dom->find('.item')->getMatches();
// Returns: [
//     ['html' => '<div class="item">1</div>', 'position' => 0, 'tag' => 'div', 'type' => 'full'],
//     ['html' => '<div class="item">2</div>', 'position' => 50, 'tag' => 'div', 'type' => 'full'],
// ]

Boolean & Integer Returns

// Count elements
$count = $dom->find('.item')->count();
echo "Found $count items";

// Check if has attribute
if ($dom->find('#app')->hasAttr('data-loaded')) {
    echo "Has data-loaded attribute";
}

// Check if has class
if ($dom->find('#app')->hasClass('active')) {
    echo "Has active class";
}

// Check if empty
if ($dom->find('.item')->isEmpty()) {
    echo "No items found";
}

// Check if not empty
if ($dom->find('.item')->isNotEmpty()) {
    echo "Items found!";
}

Setting Content

Returns: RegexNodeCollection (chainable)

// Set inner HTML (PRESERVES EXACT CONTENT - no encoding)
$dom->find('#app')->setInnerHTML('<Menu /> <Dashboard />');
// Perfect for React/Vue components!

// Set outer HTML (replace entire element)
$dom->find('#old')->setOuterHTML('<section id="new">Content</section>');
// Before: <div id="old">...</div>
// After:  <section id="new">Content</section>

// Set text (HTML encoded for safety)
$dom->find('#title')->setText('Hello & Welcome');
// Output: Hello &amp; Welcome

// Append content (add at end, inside element)
$dom->find('#list')->append('<li>New Item</li>');

// Prepend content (add at start, inside element)
$dom->find('#list')->prepend('<li>First Item</li>');

// Insert before element
$dom->find('#main')->before('<header>Header</header>');

// Insert after element
$dom->find('#main')->after('<footer>Footer</footer>');

Attributes & Classes

Returns: RegexNodeCollection (chainable)

// Set single attribute
$dom->find('#app')
    ->attr('data-component', 'main')
    ->attr('data-version', '2.0')
    ->attr('data-loaded', 'true');

// Remove attribute
$dom->find('#app')->removeAttr('data-old');

// Add single class
$dom->find('#app')
    ->addClass('active')
    ->addClass('loaded')
    ->addClass('ready');

// Add multiple classes
$dom->find('.header')->addClasses('active loaded ready');
$dom->find('.header')->addClasses(['active', 'loaded', 'ready']);

// Remove class
$dom->find('#app')
    ->removeClass('old')
    ->removeClass('hidden');

// Toggle class
$dom->find('#app')->toggleClass('active');
// If has 'active' → removes it
// If no 'active' → adds it

// Set all classes (replace existing)
$dom->find('.header')->setClasses('new-class another-class');

// Conditional class (PHP-side)
$dom->find('.header')->conditionalClass('active', $isActive);

Template Literals (React/JSX)

Single Conditional Class

$dom->find('.header')->setDynamicClass('isStick', 'sticky-fixed');

Result:

<div className={`header ${isStick ? 'sticky-fixed' : ''}`}>

Multiple Conditional Classes

$dom->find('.header')
    ->setMultipleConditionalClasses([
        'isStick' => 'sticky-fixed',
        'isTransparent' => 'transparent',
        'isScrolled' => 'scrolled'
    ]);

Result:

<div className={`header ${isStick ? 'sticky-fixed' : ''} ${isTransparent ? 'transparent' : ''} ${isScrolled ? 'scrolled' : ''}`}>

Custom Template Expression

$dom->find('.button')
    ->setTemplateExpression('className', 'btn ${type === "primary" ? "btn-primary" : "btn-secondary"}');

Result:

<button className={`btn ${type === "primary" ? "btn-primary" : "btn-secondary"}`}>

Convert class to className

$dom->find('div')->convertToClassName();

Before: <div class="header">
After: <div className="header">


Removing Elements

Returns: RegexNodeCollection (chainable)

// Remove elements from DOM
$dom->find('.old-widget')->remove();
$dom->find('#deprecated')->remove();

Iteration & Filtering

Returns: RegexNodeCollection (chainable) or transformed data

// Iterate each element
$dom->find('.item')->each(function($element, $index) {
    echo "Item $index: " . $element['html'] . "\n";
});

// Map elements (transform)
$texts = $dom->find('.item')->map(function($element, $index) {
    return strip_tags($element['html']);
});
// Returns: Collection or array

// Filter elements
$filtered = $dom->find('.item')->filter(function($element, $index) {
    return strpos($element['html'], 'active') !== false;
});
// Returns: RegexNodeCollection with filtered elements

Saving & Output

Various Return Types

// Get HTML as string
$html = $dom->html();

// Set HTML
$dom->setHtml($newHtmlString);
// Returns: XDOM (chainable)

// Save to file
$dom->saveToFile('/path/to/output.html');
// Returns: XDOM (chainable)

// Save to Laravel Storage
$dom->saveToStorage('public/output.html');
// Returns: XDOM (chainable)

// Return as Laravel Response
return $dom->toResponse();
// Returns: Response
// Automatically sets Content-Type: text/html

Advanced Usage - RegexHelper

For direct regex operations without the fluent interface:

use devoashim\regxdomdocument\RegexHelper;

Extract Content

Returns: string or null

// Extract full element (with tags)
$content = RegexHelper::extractTagContent($html, 'div', 'header', 'class');
// From: <div class="header">Content</div>
// Returns: "<div class="header">Content</div>"

$content = RegexHelper::extractTagContent($html, 'section', 'main', 'id');
// From: <section id="main">Content</section>
// Returns: "<section id="main">Content</section>"

// Extract inner content (without tags)
$inner = RegexHelper::extractInnerContent($html, 'div', 'container', 'class');
// From: <div class="container"><p>Text</p></div>
// Returns: "<p>Text</p>"

Replace Content

Returns: string

// Replace full element
$newHtml = RegexHelper::replaceTagContent(
    $html,
    'div',
    'header',
    '<div class="header"><Header /></div>'
);

// Replace inner content only
$newHtml = RegexHelper::replaceInnerContent(
    $html,
    'div',
    'content',
    '<Component />'
);

Find Multiple Elements

Returns: array

// Find all matching elements
$widgets = RegexHelper::findAllTags($html, 'div', 'widget', 'class');
// Returns: ['<div class="widget">1</div>', '<div class="widget">2</div>', ...]

foreach ($widgets as $i => $widget) {
    echo "Widget $i: $widget\n";
}

Remove Elements

Returns: string

// Remove all matching elements
$cleanHtml = RegexHelper::removeAllTags($html, 'div', 'ads', 'class');

Check Existence

Returns: bool

// Check if element exists
if (RegexHelper::hasTag($html, 'div', 'header', 'class')) {
    echo "Header exists!";
}

Attribute Helpers

Returns: array or string

// Extract all attributes from tag
$tag = '<div class="box" id="main" data-value="123">';
$attrs = RegexHelper::extractAttributes($tag);
// Returns: ['class' => 'box', 'id' => 'main', 'data-value' => '123']

// Replace attribute value
$newTag = RegexHelper::replaceAttribute($tag, 'class', 'new-box active');
// Returns: '<div class="new-box active" id="main" data-value="123">'

Template Literal Generation

Returns: string

// Convert to template literal
$reactHtml = RegexHelper::setDynamicClassName(
    $html,
    'div',
    'header',
    'isStick',
    'sticky-fixed'
);

Method Reference

XDOM Methods

| Method | Returns | Description | |--------|---------|-------------| | load($html) | XDOM | Load HTML string | | loadFromFile($path) | XDOM | Load from file | | find($selector) | RegexNodeCollection | Find elements | | html() | string | Get full HTML | | setHtml($html) | XDOM | Set HTML (chainable) | | saveToFile($path) | XDOM | Save to file (chainable) | | saveToStorage($path) | XDOM | Save to Laravel Storage | | toResponse() | Response | Return as Laravel response |

RegexNodeCollection Methods

| Method | Returns | Chainable | Description | |--------|---------|-----------|-------------| | innerHTML() | string | No | Get inner HTML | | outerHTML() | string | No | Get outer HTML | | text() | string | No | Get text content | | attr($name) | string/null | No | Get attribute value | | attr($name, $value) | RegexNodeCollection | Yes | Set attribute | | hasAttr($name) | bool | No | Check if has attribute | | removeAttr($name) | RegexNodeCollection | Yes | Remove attribute | | addClass($class) | RegexNodeCollection | Yes | Add single class | | addClasses($classes) | RegexNodeCollection | Yes | Add multiple classes | | removeClass($class) | RegexNodeCollection | Yes | Remove class | | toggleClass($class) | RegexNodeCollection | Yes | Toggle class | | setClasses($classes) | RegexNodeCollection | Yes | Set all classes | | hasClass($class) | bool | No | Check if has class | | conditionalClass($class, $condition) | RegexNodeCollection | Yes | Add class if condition true | | setInnerHTML($html) | RegexNodeCollection | Yes | Set inner HTML | | setOuterHTML($html) | RegexNodeCollection | Yes | Replace entire element | | setText($text) | RegexNodeCollection | Yes | Set text (encoded) | | append($html) | RegexNodeCollection | Yes | Append inside element | | prepend($html) | RegexNodeCollection | Yes | Prepend inside element | | before($html) | RegexNodeCollection | Yes | Insert before element | | after($html) | RegexNodeCollection | Yes | Insert after element | | remove() | RegexNodeCollection | Yes | Remove element | | setDynamicClass($var, $class) | RegexNodeCollection | Yes | Add template literal | | setMultipleConditionalClasses($array) | RegexNodeCollection | Yes | Multiple conditionals | | setTemplateExpression($attr, $expr) | RegexNodeCollection | Yes | Custom template | | convertToClassName() | RegexNodeCollection | Yes | class → className | | each($callback) | RegexNodeCollection | Yes | Iterate elements | | map($callback) | Collection/array | No | Transform elements | | filter($callback) | RegexNodeCollection | No | Filter elements | | first() | array/null | No | Get first element | | last() | array/null | No | Get last element | | get($index) | array/null | No | Get by index | | getMatches() | array | No | Get all matches | | count() | int | No | Count elements | | isEmpty() | bool | No | Check if empty | | isNotEmpty() | bool | No | Check if not empty |

RegexHelper Static Methods

| Method | Returns | Description | |--------|---------|-------------| | extractTagContent($html, $tag, $id, $type) | string/null | Extract full element | | extractInnerContent($html, $tag, $id, $type) | string/null | Extract inner content | | replaceTagContent($html, $tag, $id, $new, $type) | string | Replace full element | | replaceInnerContent($html, $tag, $id, $new, $type) | string | Replace inner content | | findAllTags($html, $tag, $id, $type) | array | Find all matching | | removeAllTags($html, $tag, $id, $type) | string | Remove all matching | | hasTag($html, $tag, $id, $type) | bool | Check if exists | | extractAttributes($tag) | array | Get all attributes | | replaceAttribute($tag, $name, $value) | string | Replace attribute value | | setDynamicClassName($html, $tag, $id, $var, $class) | string | Create template literal |

Note: $type parameter can be 'class' (default) or 'id'


Use Cases

1. React Component Conversion

$dom = XDOM::loadFromFile('template.html');

$dom->find('.header')->setInnerHTML('<Header />');
$dom->find('.navigation')->setInnerHTML('<Navigation />');
$dom->find('.content')->setInnerHTML('<Content />');
$dom->find('.footer')->setInnerHTML('<Footer />');

echo $dom->html();

2. Sticky Header with Template Literal

$dom = XDOM::loadFromFile('index.html');

$dom->find('.stricky-header')
    ->setDynamicClass('isStick', 'stricky-fixed')
    ->attr('data-component', 'header');

echo $dom->html();

3. Dynamic Navigation

$dom->find('.nav-item')
    ->setDynamicClass('isActive', 'active');

Result:

<li className={`nav-item ${isActive ? 'active' : ''}`}>

Add ref attribute to element's opening tag

 $dom->find('.main-header')->addRef('headerRef');

Before:

 <header className="main-header">

After:

 <header ref={headerRef} className="main-header">

4. Template Variable Injection

$dom = XDOM::load($template);

$dom->find('#username')->setInnerHTML('{{user.name}}');
$dom->find('#email')->setInnerHTML('{{user.email}}');
$dom->find('#role')->setInnerHTML('{{user.role}}');

return $dom->html();

5. Batch Widget Processing

$dom->find('.widget')
    ->addClass('active')
    ->addClass('featured')
    ->attr('data-loaded', 'true');

6. Complex Component Building

$dom->find('#app')
    ->setInnerHTML('<App />')
    ->addClass('loaded')
    ->addClass('active')
    ->attr('data-component', 'root')
    ->attr('data-version', '2.0')
    ->prepend('<!-- App Start -->')
    ->append('<!-- App End -->');

7. Conditional Modifications

$element = $dom->find('#app');

if ($element->hasClass('old')) {
    $element->removeClass('old')->addClass('new');
}

if (!$element->hasAttr('data-version')) {
    $element->attr('data-version', '2.0');
}

8. Extract and Replace Sections

// Extract
$header = RegexHelper::extractTagContent($html, 'div', 'header', 'class');

// Replace
$newHtml = RegexHelper::replaceTagContent(
    $html,
    'div',
    'header',
    '<header><HeaderComponent /></header>'
);

9. Navigation Menu Processing

// Find nav inside header only
$nav = $dom->find('header nav');

if ($nav->isNotEmpty()) {
    $nav->setInnerHTML('<Navigation items={menuItems} />');
}

10. Multi-Step Content Wrapping

$dom->find('#content')
    ->before('<div class="wrapper">')
    ->after('</div>')
    ->addClass('inner-content');

Method Chaining Examples

All modification methods return RegexNodeCollection, enabling powerful chaining:

// Example 1: Complete component setup
$dom->find('#app')
    ->setInnerHTML('<App />')
    ->addClass('loaded')
    ->addClass('active')
    ->attr('data-component', 'root')
    ->attr('data-version', '2.0')
    ->prepend('<!-- App Start -->')
    ->append('<!-- App End -->');

// Example 2: Style and configure widget
$dom->find('.widget')
    ->addClass('active')
    ->addClass('featured')
    ->attr('data-priority', 'high')
    ->setInnerHTML('<WidgetComponent />');

// Example 3: Update card styling
$dom->find('.card')
    ->removeClass('old-style')
    ->addClass('new-style')
    ->attr('data-updated', 'true')
    ->setInnerHTML('<CardComponent />');

Key Features

Exact Content Preservation - No HTML encoding or modification
React/Vue/JSX Support - Perfect for component templates
Template Literals - Generate dynamic className with conditionals
Template Variables - Works with {{mustache}}, {blade}, etc.
Pure Regex - Fast, lightweight, no dependencies
Method Chaining - Clean, readable code
Laravel Integration - Storage and Response helpers
No DOM Parser - Preserves exact formatting and structure


Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License.

Credits

Created by devoashim

Support

  • GitHub Issues: Create an issue
  • Documentation: Full API reference and examples included

⭐ Star Us!

If you find this package useful, please consider giving it a star on GitHub!


Remember:

  • All content is preserved EXACTLY (no encoding)
  • Perfect for React/Vue/Angular components
  • Works seamlessly with template variables
  • Pure regex - fast and lightweight
  • Method chaining for clean, maintainable code

Last Updated: 2024 Version: Complete Merged Guide

Comments