Я хотел бы создать страницу, где все изображения, которые находятся на моем веб-сайте, перечислены с заголовком и альтернативным представлением.
Я уже написал небольшую программу для поиска и загрузки всех файлов HTML, но теперь я застрял в том, как извлечь src, title и alt из этого HTML:
<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny" />Я предполагаю, что это должно быть сделано с некоторым регулярным выражением, но поскольку порядок тегов может отличаться, и мне нужны все они, я действительно не знаю, как элегантно разобрать это (я мог бы сделать это с помощью жесткого символа с помощью кстати, но это больно).






Просто чтобы дать небольшой пример использования функциональности PHP XML для этой задачи:
$doc=new DOMDocument();
$doc->loadHTML("<html><body>Test<br><img src=\"myimage.jpg\" title=\"title\" alt=\"alt\"></body></html>");
$xml=simplexml_import_dom($doc); // just to make xpath more simple
$images=$xml->xpath('//img');
foreach ($images as $img) {
echo $img['src'] . ' ' . $img['alt'] . ' ' . $img['title'];
}
Я использовал метод DOMDocument::loadHTML(), потому что этот метод может справиться с HTML-синтаксисом и не заставляет входной документ быть XHTML. Строго говоря, преобразование в SimpleXMLElement не обязательно - это просто упрощает использование xpath и результаты xpath.
Конечно, этот подход очень прост, но кто-то может захотеть использовать знак @ при вызове метода loadHTML (@ $ doc-> loadHTML), поскольку это предотвратит появление предупреждений.
Вызовите эту функцию заранее, чтобы корректно обрабатывать ошибки: libxml_use_internal_errors( true );. Вы также можете перебрать эти ошибки XML с помощью libxml_get_errors().
Если это XHTML, ваш пример, вам нужен только simpleXML.
<?php
$input = '<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny"/>';
$sx = simplexml_load_string($input);
var_dump($sx);
?>
Выход:
object(SimpleXMLElement)#1 (1) {
["@attributes"]=>
array(3) {
["src"]=>
string(22) "/image/fluffybunny.jpg"
["title"]=>
string(16) "Harvey the bunny"
["alt"]=>
string(26) "a cute little fluffy bunny"
}
}
Использование регулярного выражения для решения такого рода проблем - это плохая идея, что, вероятно, приведет к появлению неподдерживаемого и ненадежного кода. Лучше используйте HTML парсер.
В этом случае лучше разделить процесс на две части:
Я предполагаю, что ваш документ не является строгим по xHTML, поэтому вы не можете использовать синтаксический анализатор XML. НАПРИМЕР. с исходным кодом этой веб-страницы:
/* preg_match_all match the regexp in all the $html string and output everything as
an array in $result. "i" option is used to make it case insensitive */
preg_match_all('/<img[^>]+>/i',$html, $result);
print_r($result);
Array
(
[0] => Array
(
[0] => <img src = "/Content/Img/stackoverflow-logo-250.png" width = "250" height = "70" alt = "logo link to homepage" />
[1] => <img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />
[2] => <img class = "vote-down" src = "/content/img/vote-arrow-down.png" alt = "vote down" title = "This was not helpful (click again to undo)" />
[3] => <img src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt = "gravatar image" />
[4] => <img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />
[...]
)
)
Затем мы получаем все атрибуты тега img с помощью цикла:
$img = array();
foreach( $result as $img_tag)
{
preg_match_all('/(alt|title|src)=("[^"]*")/i',$img_tag, $img[$img_tag]);
}
print_r($img);
Array
(
[<img src = "/Content/Img/stackoverflow-logo-250.png" width = "250" height = "70" alt = "logo link to homepage" />] => Array
(
[0] => Array
(
[0] => src = "/Content/Img/stackoverflow-logo-250.png"
[1] => alt = "logo link to homepage"
)
[1] => Array
(
[0] => src
[1] => alt
)
[2] => Array
(
[0] => "/Content/Img/stackoverflow-logo-250.png"
[1] => "logo link to homepage"
)
)
[<img class = "vote-up" src = "/content/img/vote-arrow-up.png" alt = "vote up" title = "This was helpful (click again to undo)" />] => Array
(
[0] => Array
(
[0] => src = "/content/img/vote-arrow-up.png"
[1] => alt = "vote up"
[2] => title = "This was helpful (click again to undo)"
)
[1] => Array
(
[0] => src
[1] => alt
[2] => title
)
[2] => Array
(
[0] => "/content/img/vote-arrow-up.png"
[1] => "vote up"
[2] => "This was helpful (click again to undo)"
)
)
[<img class = "vote-down" src = "/content/img/vote-arrow-down.png" alt = "vote down" title = "This was not helpful (click again to undo)" />] => Array
(
[0] => Array
(
[0] => src = "/content/img/vote-arrow-down.png"
[1] => alt = "vote down"
[2] => title = "This was not helpful (click again to undo)"
)
[1] => Array
(
[0] => src
[1] => alt
[2] => title
)
[2] => Array
(
[0] => "/content/img/vote-arrow-down.png"
[1] => "vote down"
[2] => "This was not helpful (click again to undo)"
)
)
[<img src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt = "gravatar image" />] => Array
(
[0] => Array
(
[0] => src = "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
[1] => alt = "gravatar image"
)
[1] => Array
(
[0] => src
[1] => alt
)
[2] => Array
(
[0] => "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
[1] => "gravatar image"
)
)
[..]
)
)
Регулярные выражения интенсивно используют ЦП, поэтому вы можете захотеть кэшировать эту страницу. Если у вас нет системы кеширования, вы можете настроить свою собственную, используя ob_start и загружая / сохраняя из текстового файла.
Во-первых, мы используем preg_ match_ all, функцию, которая получает каждую строку, соответствующую шаблону, и выводит ее в третьем параметре.
Регулярные выражения:
<img[^>]+>
Мы применяем его на всех веб-страницах HTML. Его можно читать как каждая строка, которая начинается с "<img", содержит символы, отличные от ">", и заканчивается символом>.
(alt|title|src)=("[^"]*")
Применяем его последовательно к каждому тегу img. Его можно читать как каждая строка, начинающаяся с "alt", "title" или "src", затем "=", затем "" ', множество вещей, которые не являются' "'и заканчиваются'" '. Изолируйте под- строки между ().
Наконец, каждый раз, когда вы хотите иметь дело с регулярными выражениями, полезно иметь хорошие инструменты для их быстрого тестирования. Отметьте это онлайн-тестер регулярных выражений.
Обновлено: ответ на первый комментарий.
Это правда, что я не думал о людях (надеюсь, немногих), использующих одинарные кавычки.
Что ж, если вы используете только ', просто замените все «на».
Если смешать оба. Сначала вы должны дать себе пощечину :-), затем попробуйте использовать ("| ') вместо или" и [^ ø] для замены [^ "].
Проблема только в одинарных кавычках: <img src = 'picture.jpg' /> не будет работать, регулярное выражение ожидает "все время
Тре мой друг. Я добавил примечание об этом. Спасибо.
Я бы НЕ рекомендовал прокручивать вниз (хорошо, прокрутите, чтобы проверить это): хотя код кажется простым и поэтому соблазнительным для людей, DOMDocument имеет оооочень много накладных расходов, когда вы просто хотите получить атрибуты из тега. ..
Это решение хорошо, если: вы не знаете тега HTML для синтаксического анализа, у вас есть 1 строка HTML и требуется 1-2 атрибута. Загрузка DOMDoc требует больших затрат памяти, что бесполезно, если вы не разбираете весь документ.
Это не распространяется на alt=foo или alt='foo'.
Скрипт надо редактировать вот так
foreach( $result[0] as $img_tag)
потому что preg_match_all возвращает массив массивов
$url = "http://example.com";
$html = file_get_contents($url);
$doc = new DOMDocument();
@$doc->loadHTML($html);
$tags = $doc->getElementsByTagName('img');
foreach ($tags as $tag) {
echo $tag->getAttribute('src');
}
Мне любопытно, работает ли это быстрее, чем preg_match
Мне нравится, как легко это читать! xpath и regex тоже работают, но 18 месяцев спустя их уже не так легко читать.
Хотя это коротко и просто, это огромная трата ресурсов ... это означает, что использование DOMDocument для извлечения атрибутов из тега - это много (!!!) накладных расходов.
как ограничить, пример максимум 10 изображений ??
Помимо ресурсов, это зависит от варианта использования. Некоторые люди в конечном итоге пишут сотни регулярных выражений, узнав простой ответ.
это должен быть предпочтительный ответ, простой и БЕЗ РЕГЕКСА. не используйте регулярные выражения люди. здесь вы не пишете детерминированный автоматический парсер
Я использовал для этого preg_match.
В моем случае у меня была строка, содержащая ровно один тег <img> (и никакой другой разметки), которую я получил из Wordpress, и я пытался получить атрибут src, чтобы я мог запустить его через timthumb.
// get the featured image
$image = get_the_post_thumbnail($photos[$i]->ID);
// get the src for that image
$pattern = '/src = "([^"]*)"/';
preg_match($pattern, $image, $matches);
$src = $matches[1];
unset($matches);
В шаблоне для захвата заголовка или альта вы можете просто использовать $pattern = '/title = "([^"]*)"/';, чтобы захватить заголовок, или $pattern = '/title = "([^"]*)"/';, чтобы захватить альт. К сожалению, мое регулярное выражение недостаточно хорошо, чтобы захватить все три (alt / title / src) за один проход.
не будет работать, если атрибуты тега img заключены в одинарные кавычки; <img src='image.png'>
Вы не должны отвечать «в вашем случае», вы должны ответить на точный / точный вопрос ОП.
Вот решение на PHP:
Просто скачайте QueryPath и сделайте следующее:
$doc= qp($myHtmlDoc);
foreach($doc->xpath('//img') as $img) {
$src= $img->attr('src');
$title= $img->attr('title');
$alt= $img->attr('alt');
}
Вот и все, готово!
Неа. Это не РЕШЕНИЕ.
Вот функция PHP, которую я ковылял из всей вышеупомянутой информации для той же цели, а именно для настройки ширины и длины свойств тега изображения на лету ... возможно, немного неуклюже, но, похоже, работает надежно:
function ReSizeImagesInHTML($HTMLContent,$MaximumWidth,$MaximumHeight) {
// find image tags
preg_match_all('/<img[^>]+>/i',$HTMLContent, $rawimagearray,PREG_SET_ORDER);
// put image tags in a simpler array
$imagearray = array();
for ($i = 0; $i < count($rawimagearray); $i++) {
array_push($imagearray, $rawimagearray[$i][0]);
}
// put image attributes in another array
$imageinfo = array();
foreach($imagearray as $img_tag) {
preg_match_all('/(src|width|height)=("[^"]*")/i',$img_tag, $imageinfo[$img_tag]);
}
// combine everything into one array
$AllImageInfo = array();
foreach($imagearray as $img_tag) {
$ImageSource = str_replace('"', '', $imageinfo[$img_tag][2][0]);
$OrignialWidth = str_replace('"', '', $imageinfo[$img_tag][2][1]);
$OrignialHeight = str_replace('"', '', $imageinfo[$img_tag][2][2]);
$NewWidth = $OrignialWidth;
$NewHeight = $OrignialHeight;
$AdjustDimensions = "F";
if ($OrignialWidth > $MaximumWidth) {
$diff = $OrignialWidth-$MaximumHeight;
$percnt_reduced = (($diff/$OrignialWidth)*100);
$NewHeight = floor($OrignialHeight-(($percnt_reduced*$OrignialHeight)/100));
$NewWidth = floor($OrignialWidth-$diff);
$AdjustDimensions = "T";
}
if ($OrignialHeight > $MaximumHeight) {
$diff = $OrignialHeight-$MaximumWidth;
$percnt_reduced = (($diff/$OrignialHeight)*100);
$NewWidth = floor($OrignialWidth-(($percnt_reduced*$OrignialWidth)/100));
$NewHeight= floor($OrignialHeight-$diff);
$AdjustDimensions = "T";
}
$thisImageInfo = array('OriginalImageTag' => $img_tag , 'ImageSource' => $ImageSource , 'OrignialWidth' => $OrignialWidth , 'OrignialHeight' => $OrignialHeight , 'NewWidth' => $NewWidth , 'NewHeight' => $NewHeight, 'AdjustDimensions' => $AdjustDimensions);
array_push($AllImageInfo, $thisImageInfo);
}
// build array of before and after tags
$ImageBeforeAndAfter = array();
for ($i = 0; $i < count($AllImageInfo); $i++) {
if ($AllImageInfo[$i]['AdjustDimensions'] == "T") {
$NewImageTag = str_ireplace('width = "' . $AllImageInfo[$i]['OrignialWidth'] . '"', 'width = "' . $AllImageInfo[$i]['NewWidth'] . '"', $AllImageInfo[$i]['OriginalImageTag']);
$NewImageTag = str_ireplace('height = "' . $AllImageInfo[$i]['OrignialHeight'] . '"', 'height = "' . $AllImageInfo[$i]['NewHeight'] . '"', $NewImageTag);
$thisImageBeforeAndAfter = array('OriginalImageTag' => $AllImageInfo[$i]['OriginalImageTag'] , 'NewImageTag' => $NewImageTag);
array_push($ImageBeforeAndAfter, $thisImageBeforeAndAfter);
}
}
// execute search and replace
for ($i = 0; $i < count($ImageBeforeAndAfter); $i++) {
$HTMLContent = str_ireplace($ImageBeforeAndAfter[$i]['OriginalImageTag'],$ImageBeforeAndAfter[$i]['NewImageTag'], $HTMLContent);
}
return $HTMLContent;
}
Вы можете использовать простой. Большинство селекторов jQuery поддерживаются в simplehtmldom. Пример приведен ниже
// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');
// Find all images
foreach($html->find('img') as $element)
echo $element->src . '<br>';
// Find all links
foreach($html->find('a') as $element)
echo $element->href . '<br>';
Я прочитал множество комментариев на этой странице, в которых жалуются, что использование парсера dom не требует дополнительных затрат. Что ж, это может быть дороже, чем простой вызов регулярного выражения, но OP заявил, что нет никакого контроля над порядком атрибутов в тегах img. Этот факт приводит к ненужной свертке шаблона регулярного выражения. Помимо этого, использование анализатора dom обеспечивает дополнительные преимущества читабельности, удобства обслуживания и осведомленности о dom (регулярное выражение не поддерживает dom).
Мне нравятся регулярные выражения, и я отвечаю на множество вопросов о регулярных выражениях, но при работе с допустимым HTML редко есть веская причина для регулярного выражения через синтаксический анализатор.
В демонстрации ниже вы увидите, насколько просто и чисто DOMDocument обрабатывает атрибуты тега img в любом порядке со смесью кавычек (и вообще без кавычек). Также обратите внимание, что теги без целевого атрибута вообще не мешают - в качестве значения предоставляется пустая строка.
Код: (Демо)
$test = <<<HTML
<img src = "/image/fluffybunny.jpg" title = "Harvey the bunny" alt = "a cute little fluffy bunny" />
<img src='/image/pricklycactus.jpg' title='Roger the cactus' alt='a big green prickly cactus' />
<p>This is irrelevant text.</p>
<img alt = "an annoying white cockatoo" title = "Polly the cockatoo" src = "/image/noisycockatoo.jpg">
<img title=something src=somethingelse>
HTML;
libxml_use_internal_errors(true); // silences/forgives complaints from the parser (remove to see what is generated)
$dom = new DOMDocument();
$dom->loadHTML($test);
foreach ($dom->getElementsByTagName('img') as $i => $img) {
echo "IMG#{$i}:\n";
echo "\tsrc = " , $img->getAttribute('src') , "\n";
echo "\ttitle = " , $img->getAttribute('title') , "\n";
echo "\talt = " , $img->getAttribute('alt') , "\n";
echo "---\n";
}
Выход:
IMG#0:
src = /image/fluffybunny.jpg
title = Harvey the bunny
alt = a cute little fluffy bunny
---
IMG#1:
src = /image/pricklycactus.jpg
title = Roger the cactus
alt = a big green prickly cactus
---
IMG#2:
src = /image/noisycockatoo.jpg
title = Polly the cockatoo
alt = an annoying white cockatoo
---
IMG#3:
src = somethingelse
title = something
alt =
---
Использование этой техники в профессиональном коде оставит вам чистый сценарий, меньше проблем, с которыми придется бороться, и меньше коллег, которые хотели бы, чтобы вы работали где-то еще.
См. Как разбирать и обрабатывать HTML с помощью PHP?