Иметь это $html:

$html = '<p>random</p>
<a href="">Test 1</a> (target1)
<br>
<a href="">Test 2</a>  (target1)
<br>
<a href="">Test 3</a> (skip)
// etc
';

И у меня есть несколько терминов в $array:

$array = array(
    '(target1)',
    '(target2)'
);

Как я могу просмотреть $html, используя документ, чтобы найти все термины в $array и получить содержимое тега <a>, который стоит перед ним?

В итоге я получаю следующие результаты:

$results = array(
    array(
        'text' => 'Test 1',
        'needle' => 'target1'
    ),
    array(
        'text' => 'Test 2',
        'needle' => 'target1'
    )
);

Что я пробовал до сих пор

При следующем подходе мне удалось получить содержимое всех тегов <a> в $html:

$doc = new DOMDocument();
$doc->loadHTML('<?xml encoding="utf-8" ?>' . $html);
$xpath = new DOMXPath($doc);

$elements = $xpath->query('//a'); 
$el_array = array();
if ($elements->length > 0) {
    foreach($elements as $n) {
        $node = trim(strip_tags($n->nodeValue));
        if (!empty($node)) {
            $el_array[] = $node;
        }
    }
    if (!empty($el_array) && is_array($el_array)) {
    print_r($el_array);
    }
}

Но я не нашел способа получить целевые термины, чтобы я мог проверить, есть ли у нас совпадение.

2
Henrik Petterson 20 Авг 2018 в 16:19

3 ответа

Лучший ответ

Вы можете создать динамический запрос xpath с содержанием и последующим братом.

Выражение xpath будет:

//a/following-sibling::text()[contains(., '(target1)') or contains(., '(target2)')]

Например:

$array = array(
    '(target1)',
    '(target2)'
);

$contains =  implode(" or ", array_map(function($x) {
    return "contains(., '$x')";
}, $array));

$doc = new DOMDocument();
$doc->loadHTML('<?xml encoding="utf-8" ?>' . $html);
$xpath = new DOMXPath($doc);
$elements = $xpath->query("//a/following-sibling::text()[$contains]");
$results = [];

foreach ($elements as $element) {
    $results[] = [$element->previousSibling->nodeValue, trim($element->nodeValue)];
}

print_r($results);

Результат:

Array
(
    [0] => Array
        (
            [0] => Test 1
            [1] => (target1)
        )

    [1] => Array
        (
            [0] => Test 2
            [1] => (target2)
        )

)

Демо

3
The fourth bird 20 Авг 2018 в 14:11

Извините - не увидел, что для вашего решения требуется документ: /


Я думаю, это должно сработать:

$html = '
<p>random</p>
<a href="page1.php">Test 1</a> (target1)
<br>
<a href="page2.htm">Test 2</a>  (target1)
<br>
<a href="page3.html">Test 3</a> (skip)
// etc
';

$array = array(
    '(target1)',
    '(target2)'
);

#Explode HTML into new lines, to run through each line

$lines  = explode("\n", $html);

foreach ($lines as $line){

    #Find pattern from $array, and if match, use preg_match_all to find the text in the a-tag
    if(str_replace($array, '', $line) != $line){
        preg_match_all('/<a href=\".*\">(.*?)<\/a>/s', $line, $matches);

        print_r($matches[1]);
    }
}

Выход

Array
(
    [0] => Test 1
)
Array
(
    [0] => Test 2
)
0
Zacho 20 Авг 2018 в 13:42

Вы можете перебирать проанализированный dom каждый раз, когда встречаетесь, и привязывать save его значение, а затем проверять, находится ли значение узла внутри вашего массива (target1,target2), если true, хранить внутри {{X1 }} текущий узел и старый текст привязки.

<?php
    $html = '<p>random</p>
    <a href="">Test 1</a> (target1)
    <br>
    <a href="">Test 2</a>  (target1)
    <br>
    <a href="">Test 3</a> (skip)
    // etc
    ';

    $array = array(
        '(target1)',
        '(target2)'
    );

    $result = array();
    $doc = new DOMDocument();
    $doc->loadHTML('<?xml encoding="utf-8" ?>' . $html);
    $xpath = new DOMXPath($doc);
    $test = showDOMNode($doc,$array);
    print_r($result);

    function showDOMNode(DOMNode $domNode,$array,$oldval=false) {
        global  $result;
        foreach ($domNode->childNodes as $node){
            $nodename = $node->nodeName;
            $nodevalue = $node->nodeValue;
            if($nodename == "a"){
                $oldval = $nodevalue;
            }
            if(in_array(trim ($nodevalue),$array)){
                $tmp = array(
                    "text"=> $oldval,
                    "needle" =>$nodevalue
                    );
               $result[] = $tmp;
            }
            if($node->hasChildNodes()) {
                showDOMNode($node,$array,$oldval);
            }
        }    
    }

Он выводит:

Array ( 
[0] => Array ( [text] => Test 1 [needle] => (target1) ) 
[1] => Array ( [text] => Test 2 [needle] => (target1) ) 
) 
1
Nico 20 Авг 2018 в 14:02
51931648