Я ищу выражение Xpath для первого предложения в абзаце.
<p>
A federal agency is recommending that White House adviser Kellyanne Conway be
removed from federal service saying she violated the Hatch Act on numerous
occasions. The office is unrelated to Robert Mueller and his investigation.
</p>
Результат должен быть:
A federal agency is recommending that White House adviser Kellyanne Conway be
removed from federal service saying she violated the Hatch Act on numerous
occasions.
Я пробовал несколько вещей безрезультатно.
$expression = '/html/body/div/div/div/div/p//text()';
Нужно ли мне использовать: //p[ends-with
или, может быть, substring-before
?
Вы не сможете анализировать естественный язык с помощью XPath, но вы можете получить подстроку до первой точки включительно следующим образом:
substring(/p,1,string-length(substring-before(/p,"."))+1)
Обратите внимание, что это может быть не «первое предложение», если есть сокращения или другие лексические употребления точки перед окончанием первого предложения, если первое предложение заканчивается другой формой пунктуации и т. д.
Альтернативно и более кратко:
concat(substring-before(/p, "."), ".")
Умная идея Кредит:тыс. Вт в комментариях.
Думаю, я мог бы также взорвать() его и захватить первый элемент в массиве. Вероятно, пытается сделать слишком много с XPath.
Вышеупомянутое примерно так же хорошо, как вы получите в одном простом XPath; explode()
лучше не будет. Вам нужно будет использовать библиотеку NLP для работы на семантическом уровне предложений, а не на лексическом уровне пунктуации, чтобы действительно сделать это правильно.
Я думаю, что substring-before(/p,'.')
достаточно. Остальная часть выражения, чтобы получить также точку, может запутать substring-before()
семантику.
@Alejandro: Действительно, сначала я написал только substring-before(/p,'.')
, но потом я увидел, что ОП запросил, чтобы «результат был» выводом, включающим точку, поэтому я подумал, что сделаю еще один шаг. Вы правы, однако, substring-before()
важнее всего.
Вы можете просто добавить точку еще раз: concat(substring-before(/p, "."), ".")
Здесь нет действительно хорошего способа сделать это на уровне Xpath. PHP имеет только Xpath 1.0 и поддерживает только базовые строковые операции. Ничего, что может учитывать локаль/язык. Однако у самого PHP есть кое-что для этого в ext/intl
.
Поэтому извлеките текстовое содержимое узла элемента абзаца с помощью DOM+Xpath в виде строки и извлеките из него первое предложение.
IntlBreakIterator
может разделить строку в соответствии с правилами, специфичными для локали/языка.
$html = <<<'HTML'
<p>
A federal agency is recommending that White House adviser Kellyanne Conway be
removed from federal service saying she violated the Hatch Act on numerous
occasions. The office is unrelated to Robert Mueller and his investigation.
</p>
HTML;
$document = new DOMDocument();
$document->loadXML($html);
$xpath = new DOMXpath($document);
// fetch the first paragraph in the document as string
$summary = $xpath->evaluate('string((//p)[1])');
// create a break iterator for en_US sentences.
$breaker = IntlBreakIterator::createSentenceInstance('en_US');
// replace line breaks with spaces before feeding it to the breaker
$breaker->setText(str_replace(["\r\n", "\n"], '', $summary));
$firstSentence = '';
// iterate the sentences
foreach ($breaker->getPartsIterator() as $sentence) {
$firstSentence = $sentence;
// break after the first sentence
break;
}
var_dump($firstSentence);
Выход:
string(164) "A federal agency is recommending that White House adviser Kellyanne Conway be removed from federal service saying she violated the Hatch Act on numerous occasions. "
Кроме того, DOMXpath
позволяет регистрировать функции PHP и вызывать их из выражения Xpath. Если вам нужна эта логика на уровне Xpath (чтобы использовать их в условиях), это возможно.
Это полезное дополнение, использующее язык хостинга.
Вам нужно указать, какую версию XPath вы используете. Такого рода вещи намного проще в XPath 2.0 или более поздних версиях. Вы ссылаетесь на
ends-with()
, для которого требуется XPath 2.0, но вы также упоминаете PHP, который предполагает, что вы ограничены 1.0.