phphtmlxpathjssor

XPath - Query images based on whether inside specified div


We need to support two jquery based image apis, jquery.lazy to handle lazy loading of normal images, and jssor to convert multiple images into a slider, which has it's own internal mechanism to lazy load images. To make this work we need to convert the src attribute of each image to either data-src (jquery.lazy) or src2 (jssor).

The html looks something like this:

<div id="campaign-content">
    <div id="slide-show-1" class="embedded-slider-wrap">
        <div>
             <img src="/path/to/1.jpg" />
        </div>
        <div>
             <img src="/path/to/2.jpg" />
        </div>
    </div>
    <figure>
         <img src="/path/to/3.jpg" />
    </figure>
    <div id="slide-show-2" class="embedded-slider-wrap">
        <div>
             <img src="/path/to/4.jpg" />
        </div>
        <div>
             <img src="/path/to/5.jpg" />
        </div>
    </div>
</div>

The goal is to issue two xpath queries, one for all images within divs flagged as a slider-wrap (of which there may be multiple) and all images that are NOT contained within a slider-wrap div.

To reduce the complexity of the the xpath query, I was thinking it might be easier to query for just slide images, then query for all images, like:

$imagesSlide = $xpath->query(sprintf('//div[@id="%s"]//div[@class="embedded-slider-wrap"]//img', $id));
$imagesOther = $xpath->query(sprintf('//div[@id="%s"]//img', $id));

Then step through each one and set the correct attribute(data-src or src2). The problem I am having is, the xpath query for $imagesOther returns all images (expected), whereas the xpath query for $imagesSlide does not.

Also, I tried to do a NOT xpath query so I wouldn't have to do any extra processing with the ALL images query, but couldn't get it to work as expected either, it looks like:

$images = $xpath->query(sprintf('//div[@id="%s"]//img[not(ancestor::div/@class="embedded-slider-wrap")]', $id));

Solution

  • Solved the issue. I was approaching the xpath query the same way I approach jquery element selectors. What I didn't mention in the OP is the embedded-slider-wrap class was not the only class applied to the div (honestly didn't think it mattered b/c jQuery can select elements having multiple classes).

    Apparently, XPath won't match the query for an element based on class name if the element has multiple classes, instead you have to do the following:

    // Element with multiple classes
    <div class="embedded-slider-wrap some-other-class">
        <img src="/path/to/image/1.png" />
    
    // Non working Xpath query
    //img[ancestor::div[@class="embedded-slider-wrap"]]//img
    
    // Working Xpath query
    //img[ancestor::div[contains(@class, "embedded-slider-wrap")]]