Как извлечь текст, используя XPath между тегом и некоторым конечным тегом - PullRequest
0 голосов
/ 03 мая 2020

Я дал следующее HTML. Имена классов всегда одинаковы. Только текст между тегами меняется и имеет разную длину и содержание.

<a>
    <span class="xxx">Not this text <span class="yyy">not this text</span> <span class="zzz">This is</span> the required text <q class="aaa">this not</q></span>
</a>

Как извлечь содержимое между тегом с классом "zzz" и концом строки, но элементом с классом "aaa" "не следует ли не включить в результат? Возможно ли это?

Элемент с классом "aaa" может существовать или нет:

<a>
    <span class="xxx">Not this text <span class="yyy">not this text</span> <span class="zzz">This is</span> the required text</span>
</a>

Ожидаемый результат должен быть:

This is the required text 

Также часть " требуемый текст "может существовать или нет:

<a>
    <span class="xxx">Not this text <span class="yyy">not this text</span> <span class="zzz">This is</span></span>
</a>

, поэтому результат должен быть:

This is

Я пытаюсь это сделать в PHP, используя DOMXPath.

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Решение XPath:

$xml = <<<'XML'
<a><span class="xxx">Not this text <span class="yyy">not this text</span> <span class="zzz">This is</span> the required text</span></a>
XML;
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$elements = $xpath->query('//text()[parent::*[not(@class="aaa")]][preceding::span[@class="yyy"]][normalize-space()]');
foreach($elements as $element)
echo $element->nodeValue;

Вывод:

This is the required text
0 голосов
/ 03 мая 2020

Я не знаю, как сделать это с XPath, обязательно, но вот способ, которым вы могли бы сделать это без XPath.

function walk(DOMNode $node, $skipParent = false) {
    if (!$skipParent) {
        yield $node;
    }
    if ($node->hasChildNodes()) {
        foreach ($node->childNodes as $n) {
            yield from walk($n);
        }
    }
}

$html = <<<'HTML'
<span class="xxx">
    Not this text
    <span class="yyy">not this text</span>
    <span class="zzz">This is</span>
    the required text
    <q class="aaa">this not</q>
</span>
HTML;

$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$count = 0;
foreach(walk($dom->firstChild) as $node) {
    if (!($node instanceof DOMText) && $node->hasAttribute('class') && $node->getAttribute('class') === 'xxx') {
        foreach(walk($node) as $n) {
            if (isset($content)) {
                $count++;
            }
            if (!($n instanceof DOMText) && $n->hasAttribute('class') && $n->getAttribute('class') === 'zzz') {
                $content = $n->textContent;
            }
            if (isset($content) && $n instanceof DOMText && $count == 2) {
                $content .= " " . $n->textContent;
                break 2;
            }
        }
    }
}

var_dump($content);

Это дает желаемый результат независимо от того, "the required text" часть есть.

...