Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Css Selector Laravel Package

symfony/css-selector

Symfony CssSelector converts CSS selectors into XPath expressions, enabling CSS-style element matching in XML/HTML documents. Ported from the Python cssselect library, it’s a lightweight component for selector parsing and XPath generation in PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package via Composer:

    composer require symfony/css-selector
    
  2. Basic usage (convert CSS to XPath):

    use Symfony\Component\CssSelector\CssSelectorConverter;
    use Symfony\Component\CssSelector\XPathNodeConverter;
    
    $converter = new CssSelectorConverter();
    $xpathConverter = new XPathNodeConverter();
    
    $cssSelector = 'div.is-active > p';
    $xpath = $converter->toXPath($cssSelector);
    
    // Example output: `//div[contains(@class, 'is-active')]/p`
    
  3. First use case: Query a DOM document with CSS-like syntax:

    $dom = new DOMDocument();
    $dom->loadHTML('<div class="is-active"><p>Hello</p></div>');
    
    $xpath = $converter->toXPath('div.is-active > p');
    $nodes = $dom->xpath($xpath);
    
    // $nodes now contains the <p> element
    

Where to Look First

  • Official Documentation for selector syntax support and edge cases.
  • CssSelectorConverter class for core conversion logic.
  • XPathNodeConverter for translating node names/attributes to XPath (e.g., div#id//div[@id='id']).

Implementation Patterns

Core Workflows

1. DOM Scraping with CSS Selectors

use Symfony\Component\CssSelector\CssSelectorConverter;
use Symfony\Component\DomCrawler\Crawler;

$converter = new CssSelectorConverter();
$crawler = new Crawler('<html><body><div class="user">John</div></body></html>');

// Convert CSS to XPath and query
$xpath = $converter->toXPath('div.user');
$nodes = $crawler->filterXPath($xpath); // Symfony DomCrawler method

// Or use native DOMDocument
$dom = new DOMDocument();
$dom->loadHTML($html);
$nodes = $dom->xpath($xpath);

2. Testing with CSS Selectors

use Symfony\Component\CssSelector\CssSelectorConverter;
use PHPUnit\Framework\Assert;

$converter = new CssSelectorConverter();
$dom = new DOMDocument();
$dom->loadHTML('<div data-test="user">Test</div>');

$xpath = $converter->toXPath('[data-test="user"]');
$nodes = $dom->xpath($xpath);

Assert::count(1, $nodes);

3. Laravel Service Provider Integration

// app/Providers/AppServiceProvider.php
use Symfony\Component\CssSelector\CssSelectorConverter;

public function register()
{
    $this->app->singleton(CssSelectorConverter::class, function ($app) {
        return new CssSelectorConverter();
    });
}

// Usage in controllers/services
$converter = app(CssSelectorConverter::class);
$xpath = $converter->toXPath('h1.title');

Integration Tips

  • Cache XPath results for performance-critical scraping:
    $cache = new \Symfony\Component\Cache\Simple\FilesystemCache();
    $converter = new CssSelectorConverter($cache);
    
  • Combine with spatie/array-to-xml for XML scraping:
    use Spatie\ArrayToXml\ArrayToXml;
    $xml = ArrayToXml::convert(['user' => ['name' => 'John']]);
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    $xpath = $converter->toXPath('user.name');
    
  • Use with Laravel Collective HTML for form/scraper interactions:
    use Collective\Html\HtmlFacade;
    $html = HtmlFacade::script()->withContent('<script>...</script>');
    $dom = new DOMDocument();
    $dom->loadHTML($html);
    

Gotchas and Tips

Pitfalls

  1. PHP 8.4 Requirement:

    • The package requires PHP 8.4+ (added in v8.0.0). If your Laravel project uses PHP 8.2/8.3, you’ll need to:
      • Upgrade PHP (recommended for long-term support).
      • Use a polyfill (none officially supported; consider a custom lightweight parser for basic selectors).
      • Stick with native DOM methods or basic XPath.
  2. Memory Leaks in High-Volume Scraping:

    • Older versions (<v7.4.6) could exhaust memory with repeated selector conversions. Solution:
      $cache = new \Symfony\Component\Cache\Adapter\FilesystemAdapter();
      $converter = new CssSelectorConverter($cache);
      
    • The LRU cache (added in v7.4.6) mitigates this but may not be enabled by default in all Symfony versions.
  3. Selector Syntax Limitations:

    • Not all CSS selectors are supported. Test edge cases:
      // Works: div.is-active > p
      // May fail: div:has(> p) // Requires v7.1.0+ (Symfony 5.4+)
      
    • Check the documentation for supported features.
  4. XPath vs. CSS Quirks:

    • CSS > (child combinator) becomes / in XPath, while CSS (descendant) becomes //.
    • Attribute selectors like [href^="https"] may not translate 1:1 to XPath. Workaround:
      // CSS: a[href^="https"]
      // XPath: //a[starts-with(@href, 'https')]
      
  5. Symfony DomCrawler Dependency:

    • While the package is standalone, full integration with symfony/dom-crawler requires:
      composer require symfony/dom-crawler
      
    • Avoid if you’re using pure Laravel DOM tools (e.g., php-dom).

Debugging Tips

  • Validate XPath output:
    $xpath = $converter->toXPath('div.is-active');
    echo $xpath; // Debug the generated XPath
    
  • Test with DOMXPath:
    $dom = new DOMDocument();
    $dom->loadHTML('<div class="test">Hello</div>');
    $xpath = new DOMXPath($dom);
    $nodes = $xpath->query($converter->toXPath('div.test'));
    
  • Handle malformed selectors:
    try {
        $xpath = $converter->toXPath('invalid[selector');
    } catch (\Symfony\Component\CssSelector\Exception\ParseErrorException $e) {
        // Log or handle gracefully
    }
    

Extension Points

  1. Custom XPath Post-Processing:
    • Override the converter’s output:
      $xpath = $converter->toXPath('div.is-active');
      $xpath = str_replace('//div', '/html/body/div', $xpath); // Force absolute path
      
  2. Extend Selector Support:
    • Fork the package or use a wrapper to add custom rules (e.g., Laravel-specific pseudo-selectors).
  3. Performance Optimization:
    • Pre-compile selectors in a service container:
      $this->app->when(CssSelectorConverter::class)
          ->needs('$cache')
          ->give(function () {
              return new \Symfony\Component\Cache\Adapter\ArrayAdapter();
          });
      
  4. Laravel Facade Wrapper:
    // app/Facades/CssSelector.php
    use Illuminate\Support\Facades\Facade;
    
    class CssSelector extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'css.selector.converter';
        }
    }
    
    // Usage: CssSelector::toXPath('div.is-active');
    

Laravel-Specific Quirks

  • Service Container Conflicts:
    • If using Symfony’s DomCrawler, register it after the converter to avoid DI conflicts:
      $this->app->singleton(DomCrawler::class, function ($app) {
          $converter = $app->make(CssSelectorConverter::class);
          return new DomCrawler($html, $converter);
      });
      
  • Blade Directives:
    • Create a Blade directive for quick XPath generation:
      Blade::directive('xpath', function ($selector) {
          return "<?php echo app('css.selector.converter')->toXPath({$selector}); ?>";
      });
      
      Usage: @xpath('div.is-active') in Blade templates.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
redaxo/debug
redaxo/test
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder