Adam Strags
Adam Strags

Reputation: 23

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.

Upvotes: 1

Views: 36

Answers (1)

IT goldman
IT goldman

Reputation: 19485

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);

Upvotes: 0

Related Questions