2015-02-28 2 views
1

Я хочу, чтобы заменить содержимое элемента с содержимым, которое definded в $ tagsReplace массиве, но есть проблема с preg_replace, моя текущая одой:Как заменить значение внутри тега html?

$tagsReplace = array(
    'header' => 'header', 
    'tag1' => 'this is tag1', 
    'tag2' => 'this is tag2', 
    'tag3' => 'this is tag3', 
    'footer' => 'footer', 
); 

$content = ' 
<!DOCTYPE html> 
<hthml> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1"></div> 
<div data-edit="true" data-tag-id="tag2"></div> 
<div data-edit="true" data-tag-id="tag3"></div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 
'; 

$dom = new DOMDocument(); 
libxml_use_internal_errors(true); 
$dom->loadHTML($content); 
$xpath = new DomXpath($dom); 

foreach ($xpath->query('//*[@data-edit="true"]') as $rowNode) { 
    $tagID = $rowNode->getAttribute('data-tag-id'); 
    $content = preg_replace('/(<div.*?data-edit="true"[^>]*>)(.*?)(<\/div>)/i', '$1'. $tagsReplace[$tagID] . '$3', $content); 
} 
echo $content; 

Что я хочу, чтобы получить выход так:

<!DOCTYPE html> 
<hthml> 
<header data-edit="true" data-tag-id="header">header</header> 
<div data-edit="true" data-tag-id="tag1">this is tag1</div> 
<div data-edit="true" data-tag-id="tag2">this is tag2</div> 
<div data-edit="true" data-tag-id="tag3">this is tag3</div> 
<footer data-edit="true" data-tag-id="footer">footer</footer> 
</html> 

Текущий результат:

<!DOCTYPE html> 
<hthml> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1">footer</div> 
<div data-edit="true" data-tag-id="tag2">footer</div> 
<div data-edit="true" data-tag-id="tag3">footer</div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 

Soo все элементы, которые содержат atribute данных редактируемых = «истинный» и данных мечения-идентификатор, чтобы получить содержимое внутри m заменяется значением tagid, которое дефинируется в arra $ tagsReplace.

ответ

2

Потому что вы задаете DIV в шаблоне preg_match и мы знайте, что первое элемент начинается с заголовка, поэтому он не будет соответствовать , поэтому просто замените «div» в начале шаблона preg_match на (. *?), чтобы соответствовать заголовку и даже другим словам. это:

$ содержание = preg_replace ('.?/(< ДИВданных редактировать = "истина" [^>]>) (*) (</DIV>)/я.? , '$ 1'. $ TagsReplace [$ tagID]. '$ 3', $ content);

становится:.?.?

$ содержание = preg_replace ('/ (< (*) данных редактировать = "истина" [^>] >) () (</DIV>)/i ',' $ 1 '. $ tagsReplace [$ tagID].' $ 3 ', $ content);

Другой вариант доступен вы можете использовать preg_replace_callback (модель, функция, предмет) делать то, что вы хотите волшебно, вот это решение, которое работает для меня:

$content = ' 
<!DOCTYPE html> 
<hthml> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1"></div> 
<div data-edit="true" data-tag-id="tag2"></div> 
<div data-edit="true" data-tag-id="tag3"></div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 
'; 

$pattern = '/<(.+) data-edit="true" data-tag-id="(.*)"(.*?)>(.*?)<\/(.+)>/'; 
$another = preg_replace_callback($pattern, function($matches){ 
    $tagsReplace = array(
     'header' => 'header1', 
     'tag1' => 'this is tag1', 
     'tag2' => 'this is tag2', 
     'tag3' => 'this is tag3', 
     'footer' => 'footer', 
    ); 
    return '<'.$matches[1].' data-edit="true" data-tag-id="'.$matches[2].'"'.$matches[3].'>'.$tagsReplace[$matches[2]].'<\/'.$matches[5].'>/'; 
}, $content); 
# before the replacement 
print_r($content); 
echo '\n'; 
// another holds the content after replacement 
print_r($another); 
1

Вы не можете всегда заменять одного и того же патрона, потому что у вас есть 3 разных тега.

Посмотрите на этот код:

<?php 

$tagsReplace = array(
    'header' => 'header', 
    'tag1' => 'this is tag1', 
    'tag2' => 'this is tag2', 
    'tag3' => 'this is tag3', 
    'footer' => 'footer', 
); 

$content = ' 
<!DOCTYPE html> 
<html> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1"></div> 
<div data-edit="true" data-tag-id="tag2"></div> 
<div data-edit="true" data-tag-id="tag3"></div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 
'; 

$dom = new DOMDocument(); 
libxml_use_internal_errors(true); 
$dom->loadHTML($content); 
$xpath = new DomXpath($dom); 

$html = explode("\n", trim($content)); 
$i = 2; 

foreach ($xpath->query('//*[@data-edit="true"]') as $rowNode) { 
    $tagID = $rowNode->getAttribute('data-tag-id'); 

    switch ($rowNode->nodeName) { 
     case 'header': 
     $html[$i] = preg_replace('/(<header.*?data-edit="true"[^>]*>)(.*?)(<\/header>)/i', '$1'. $tagsReplace[$tagID] . '$3', $html[$i]); 
     break; 

     case 'div': 
     $html[$i] = preg_replace('/(<div.*?data-edit="true"[^>]*>)(.*?)(<\/div>)/i', '$1'. $tagsReplace[$tagID] . '$3', $html[$i]); 
     break; 

     case 'footer': 
     $html[$i] = preg_replace('/(<footer.*?data-edit="true"[^>]*>)(.*?)(<\/footer>)/i', '$1'. $tagsReplace[$tagID] . '$3', $html[$i]); 
     break; 
    } 
    $i++; 
} 

$content = implode("\n", $html); 

echo $content; 

?> 
+0

Вы по-прежнему собираете все 3 divs с одинаковым значением, потому что вы не назвали идентификатор тега данных в регулярном выражении. –

+0

Вы запустили код? результат похож на него. –

+0

Извинения. Я не заметил, что вы взорвали его в разные строки, а затем выполняли регулярное выражение по каждой линии в отдельности. Поэтому вы правы в том, что он работает с этими точными данными. Однако, что произойдет, если вы представите что-то простое, как пустая строка перед одним из divs - ничего не синхронизировать $ i и $ rowNode в синхронизации ... –

2

Чтобы получить результат, который вы хотите вы могли бы цикл через массив замены и поиск как data-edit = true и data-tag-id = <key> в том же XPath запроса, а затем заменить значение узла , Таким образом, вам не нужно использовать preg_replace.

$content = ' 
<!DOCTYPE html> 
<html> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1"></div> 
<div data-edit="true" data-tag-id="tag2"></div> 
<div data-edit="true" data-tag-id="tag3"></div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 
'; 

$tagsReplace = array(
    'header' => 'header', 
    'tag1' => 'this is tag1', 
    'tag2' => 'this is tag2', 
    'tag3' => 'this is tag3', 
    'footer' => 'footer', 
); 

$dom = new DOMDocument(); 
libxml_use_internal_errors(true); 
$dom->loadHTML($content); 
$xpath = new DomXpath($dom); 

foreach ($tagsReplace as $key => $value) { 
    $nodes = $xpath->query(
     '//*[@data-edit="true" and @data-tag-id="' . $key . '"]' 
    ); 

    if ($nodes->length) { 
     $nodes->item(0)->nodeValue = $value; 
    } 
} 

$dom->formatOutput = true; 
echo $dom->saveHTML(); 

Выход:

<!DOCTYPE html> 
<html><body> 
<header data-edit="true" data-tag-id="header">header</header> 
<div data-edit="true" data-tag-id="tag1">this is tag1</div> 
<div data-edit="true" data-tag-id="tag2">this is tag2</div> 
<div data-edit="true" data-tag-id="tag3">this is tag3</div> 
<footer data-edit="true" data-tag-id="footer">footer</footer> 
</body></html> 
2

Попробуйте это, он принимает любой тип тега

$tagsReplace = array(
    'header' => 'header', 
    'tag1' => 'this is tag1', 
    'tag2' => 'this is tag2', 
    'tag3' => 'this is tag3', 
    'footer' => 'footer', 
); 

$content = ' 
<!DOCTYPE html> 
<html> 
<header data-edit="true" data-tag-id="header"></header> 
<div data-edit="true" data-tag-id="tag1"></div> 
<div data-edit="true" data-tag-id="tag2"></div> 
<div data-edit="true" data-tag-id="tag3"></div> 
<footer data-edit="true" data-tag-id="footer"></footer> 
</html> 
'; 

$dom = new DOMDocument(); 
libxml_use_internal_errors(true); 
$dom->loadHTML($content); 
$xpath = new DomXpath($dom); 

foreach ($xpath->query('//*[@data-edit="true"]') as $rowNode) { 
    $tagID = $rowNode->getAttribute('data-tag-id'); 
    $content = preg_replace('/(<(.*?) [^>]*?data-tag-id="'.$tagID.'"[^>]*>)(.*?)(<\/\2>)/i', '$1'. $tagsReplace[$tagID] . '$4', $content); 
} 
echo $content; 
+0

Часть вашего регулярного выражения, которая идентифицирует тэг, позволяет ему выйти за пределы этого <>. Лучше указать что-то вроде '(?: Div | header | footer)' или тому подобное или, по крайней мере, '[^] *', чтобы остановиться, когда вы дойдете до места. Лучше всего было бы получить тэг ($ rowNode-> tagName?), А затем указать это конкретно. –

+0

Согласен, вы правы – HandyDan

2
foreach ($xpath->query('//*[@data-edit="true"]') as $rowNode) { 
    $rowNode->nodeValue = $tagsReplace[$rowNode->getAttribute('data-tag-id')]; 
} 
echo $dom->saveHTML(); 
1

Не следует использовать регулярное выражение для разбора/изменить HTML или XML. Вы уже используете DOM, поэтому почему бы не использовать его для изменения документа?

$dom = new DOMDocument(); 
libxml_use_internal_errors(true); 
$dom->loadHTML($content); 
$xpath = new DOMXPath($dom); 

foreach ($xpath->evaluate('//*[@data-edit="true"]') as $rowNode) { 
    // read id attribute 
    $tagId = $rowNode->getAttribute('data-tag-id'); 
    // remove all child nodes 
    $rowNode->nodeValue = ''; 
    // if here is a new content available 
    if (isset($tagsReplace[$tagId])) { 
     // create a text node and append it 
     $rowNode->appendChild(
     $dom->createTextNode($tagsReplace[$tagId]) 
    ); 
    } 
} 
echo $dom->saveHtml(); 

Output (отформатированные):

<!DOCTYPE html> 
<html> 
    <body> 
    <header data-edit="true" data-tag-id="header">header</header> 
    <div data-edit="true" data-tag-id="tag1">this is tag1</div> 
    <div data-edit="true" data-tag-id="tag2">this is tag2</div> 
    <div data-edit="true" data-tag-id="tag3">this is tag3</div> 
    <footer data-edit="true" data-tag-id="footer">footer</footer> 
    </body> 
</html> 

Внимание!: HTML выглядит как HTML5 и не полностью совместим с реализацией PHP DOM. Вам может понадобиться library для импорта/экспорта HTML5 в DOMDocument как XHTML.