phpdomxpath

xpath selection of <p><a></a></p> but not <p>sometext<a>link</a>or some text</p>


so I need to inject an 'inlineAssetLink' class into an anchor tag that is part of a paragraph, but a class of 'blockAssetLink' into an anchor tag that is inside an otherwise empty paragraph.

Not sure this is even possible with xpath, but the content comes from a WYSIWYG editor in cms and I'd like to do this server-side rather than with javascript.

Already using DOMXPath to manipulate other parts of content so it would be nice to do the same for this.


Solution

  • Here's code that will load this into DOMDocument and will apply those classes to all anchors, by checking count of children of parent of each.

    function addClassesToAnchors($html)
    {
        $dom = new DOMDocument();
        $dom->loadHTML(
            "<div class='my-wrapper'>$html</div>",
            LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
        );
    
        // get all anchors
        $anchors = $dom->getElementsByTagName('a');
    
        foreach ($anchors as $anchor) {
            $parentNode = $anchor->parentNode;
    
            if ($parentNode->nodeName == 'p') {
                $childNodes = $parentNode->childNodes;
    
                // count children, expect 1 for empty p
                $count = 0;
                foreach ($childNodes as $childNode) {
                    $count++;
                }
    
                if ($count == 1) {
                    $anchor->setAttribute('class', 'blockAssetLink');
                }
                if ($count > 1) {
                    $anchor->setAttribute('class', 'inlineAssetLink');
                }
            }
        }
    
        // Get the content as HTML without the <div> wrapper
        $divElement = $dom->documentElement;
        $result = '';
        foreach ($divElement->childNodes as $node) {
            $result .= $dom->saveHTML($node);
        }
    
        return $result;
    }
    
    $html = "<p><a></a></p> <p>but not</p> <p>sometext<a>link</a>or some text</p>";
    echo addClassesToAnchors($html);