PHP с DOM Xpath - удалить дочерний узел и упорядочить строку

У меня есть эта структура html:

<html>
  <body>
    <section>
      <div>
        <div>
          <section>
            <div>
              <table>
                <tbody>
                  <tr></tr>
                  <tr>
                    <td></td>
                    <td></td>
                    <td>
                      <i></i>
                      <div class="first-div class-one">
                        <div class="second-div"> soft </div>
                        130 cm / 15cm
                      </div>
                    </td>
                  </tr>
                  <tr></tr>
                </tbody>
              </table>
            </div>
          </section>
        </div>
      </div>
    </section>
  </body>
</html>

Теперь у меня есть этот код XPath:

$doc = new DOMDocument();
@$doc->loadHtmlFile('http://www.whatever.com');
$doc->preserveWhiteSpace = false;

$xpath = new DOMXPath( $doc );

$nodelist = $xpath->query( '/html/body/section/div[2]/section/div/table/tbody/tr[2]/td[3]/div' );
foreach ( $nodelist as $node ) {
    $result = $node->nodeValue."\n";
}

В результате я получаю «мягкие 130 см / 15 см».

Но я хочу знать, как получить только «15», поэтому мне нужно:

<сильный>1. Чтобы узнать, как избавиться от childNode->nodeValue

<сильный>2. Если у меня есть «130 см / 15 см», чтобы узнать, как получить только «15» в качестве значения узла переменной в PHP.

Вы можете помочь? заранее спасибо


person Karls    schedule 01.02.2016    source источник
comment
nodeValue — это просто текстовая строка. Работа DOM выполнена, когда у вас есть эта строка - вам нужно будет использовать стандартные строковые операции PHP (например, substr), чтобы манипулировать ею, а затем вставить измененную строку обратно в DOM.   -  person Marc B    schedule 01.02.2016
comment
Да, именно поэтому в заголовке написано «php с dom xpath». Я знаю, что делать, если я хочу получить только «130», но не если я хочу только «15». Кроме того, первое, что мне нужно, это удалить значение «soft» дочернего элемента div, что является вещью dom xpath. Также подстроки, окружающие «15», могут измениться в реальном html-коде, с которым я работаю.   -  person Karls    schedule 01.02.2016
comment
и я говорю вам, что у вас есть строка 130 cm /15cm, и теперь вам нужно использовать стандартные операции со строками php, чтобы еще больше разбить ее. что означает, что технически ваш вопрос не имеет НИЧЕГО общего с dom. dom сделал свое дело, теперь вам нужны ДРУГИЕ инструменты.   -  person Marc B    schedule 01.02.2016
comment
У меня пока нет «130 см/15 см». У меня ‘мягкие 130 см/15см’. Пожалуйста, прочитайте исходный вопрос.   -  person Karls    schedule 01.02.2016
comment
@MarcB, я думаю, вы не читали, что есть дочерний div, значение которого «мягкое». Это была первая часть моего вопроса.   -  person Karls    schedule 01.02.2016


Ответы (1)


Текст внутри тега также является узлом (дочерним), в частности, DOMText. Посмотрев на потомков этого div, вы можете найти DOMText и получить его nodeValue. Пример ниже:

$doc = new DOMDocument();
$doc->loadHTML("<html><body><p>bah</p>Test</body></html>");
echo $doc->saveHTML();

$xpath = new DOMXPath( $doc );
$nodelist = $xpath->query( '/html/body' );
foreach ( $nodelist as $node ) {
    if ($node->childNodes)
            foreach ($node->childNodes as $child) {
                    if($child instanceof DOMText)
                            echo $child->nodeValue."\n"; // should output "Test".
            }
}

Второй пункт можно легко выполнить с помощью регулярных выражений:

$string = "130 cm / 15cm";

$matches = array();
preg_match('|/ ([0-9]+) ?cm$|', $string, $matches);

echo $matches[1];

Полное решение:

<?php

$strhtml = '
<html>
  <body>
    <section>
      <div>
        <div>
          <section>
            <div>
              <table>
                <tbody>
                  <tr></tr>
                  <tr>
                    <td></td>
                    <td></td>
                    <td>
                      <i></i>
                      <div class="first-div class-one">
                        <div class="second-div"> soft </div>
                        130 cm / 15cm
                      </div>
                    </td>
                  </tr>
                  <tr></tr>
                </tbody>
              </table>
            </div>
          </section>
        </div>
      </div>
    </section>
  </body>
</html>';

$doc = new DOMDocument();
@$doc->loadHTML($strhtml);
echo $doc->saveHTML();

$xpath = new DOMXPath( $doc );
$nodelist = $xpath->query( '/html/body/section/div/div/section/div/table/tbody/tr[2]/td[3]/div' );
foreach ( $nodelist as $node ) {
    if ($node->childNodes)
        foreach ($node->childNodes as $child) {
            if($child instanceof DOMText && trim($child->nodeValue) != "")
            {
                echo 'Raw: '.trim($child->nodeValue)."\n";
                $matches = array();
                preg_match('|/ ([0-9]+) ?cm$|', trim($child->nodeValue), $matches);
                echo 'Value: '.$matches[1]."\n";
            }
       }
}
person Weboide    schedule 01.02.2016
comment
Weboide, спасибо за помощь. Ваш базовый пример отлично работает, как и ожидалось. Но вот результат, который я получаю с вашим кодом: var_dump я добавил в конце. Если я удалю var_dump, он ничего не выведет. - person Karls; 01.02.2016
comment
Ваш xpath был неправильным с первым div[2], смотрите мои правки, я добавил полное решение. Не забудьте проголосовать и выбрать мой ответ, если это решило вашу проблему, спасибо! - person Weboide; 01.02.2016