Search code examples
phpxpathdomdocument

Find setting in CSS with PHP xPath


I'm trying to find the color of a span in a link set in the CSS of the following HTML example using DOMDocument/xPath:

   <html>
      <head>
          <style>
             a span{
                color: #21d;
             }
          </style>
      </head>
      <body>
          <a href='test.html'>this is a <span>test</span></a>
      </body>
   </html>

I can find all CSS with the xPath '//style' ($css = $path->query( '//span' )->nodeValue) and then do something with a pregmatch to get the result, but wonder if there is a way to get this color using xPath, and if so, what that way is.


Solution

  • XPath is not particularly well adapted to this kind of task, but contrary to what's been put forth in the comments it is possible using evaluate() and some nested string functions like substring-before() and substring-after():

    $html = '
        <html>
          <head>
              <style>
                 a span{
                    background-color: #ddd;
                    color: #21d;
                 }
              </style>
          </head>
          <body>
              <a href="test.html">this is a <span>test</span></a>
          </body>
       </html>
    ';
    
    $dom = new DOMDocument();
    $dom->loadHTML($html);
    $xpath = new DomXPath($dom);
    
    $result = $xpath->evaluate("
        substring-before(
            substring-after(
                substring-after(
                    normalize-space(//style/text())
                , 'a span')
            ,' color:')
        ,';')
    ");
    echo $result;
    

    OUTPUT:

    #21d

    Working from the inside out:

    1. Normalize whitespace.
    2. Get the part of the style text after your selector.
    3. Get the text after the css rule in question. Notice I added a space before ' color:' to avoid possibly getting background-color or the like. Normalizing the space in step one makes this work even if color: was preceded by a tab.
    4. get the string before the final ; of the color rule.

    I'm pretty sure there are a slew of potential points of failure here and I wouldn't recommend using XPath for something like this but it's an interesting exercise all the same.