【问题标题】:How replace the value inside a html tag?如何替换html标签内的值?
【发布时间】:2015-05-01 10:29:35
【问题描述】:

我想用 $tagsReplace 数组中定义的内容替换元素内容,但 preg_replace 有问题,我当前的 ode:

$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>

所有包含属性 data-edit="true" 和 data-tag-id 的元素都必须将其中的内容替换为在 arra $tagsReplace 中定义的 tagid 值。

【问题讨论】:

    标签: php html regex dom preg-replace


    【解决方案1】:

    因为您指定 div 在您的 preg_match 模式中 我们知道第一个元素以 header 开头,所以它不会被匹配 因此,只需将 preg_match 模式开头的“div”替换为 (.*?) 即可匹配标题甚至其他单词。 这个:

    $content = preg_replace('/(div.?data-edit="true"[^>]>)(.*?)( div>)/i', '$1'. $tagsReplace[$tagID] . '$3', $content);

    变成:

    $content = preg_replace('/((.*?) data-edit="true"[^>]>)(.?)()/i', '$1'. $tagsReplace[$tagID] . '$3', $content);

    另一个选项是可用的,你可以使用 preg_replace_callback(pattern,function,subject) 来做你想做的事情,这是一个对我有用的解决方案:

    $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);
    

    【讨论】:

      【解决方案2】:

      要获得您想要的结果,您可以遍历替换数组并在同一个 XPath 查询中搜索 data-edit = truedata-tag-id = &lt;key&gt;,然后替换节点值。这样你就完全不用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>
      

      【讨论】:

        【解决方案3】:

        试试这个,它接受任何类型的标签

        $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;
        

        【讨论】:

        • 正则表达式中标识标记名的部分允许它直接在 之外。最好指定(?:div|header|footer) 之类的东西,或者至少[^ ]* 当你到达一个空间时停止。更好的是获取标记名($rowNode->tagName ?),然后具体指定。
        【解决方案4】:
        foreach ($xpath->query('//*[@data-edit="true"]') as $rowNode) {
            $rowNode->nodeValue = $tagsReplace[$rowNode->getAttribute('data-tag-id')];
        }
        echo $dom->saveHTML();
        

        【讨论】:

          【解决方案5】:

          你不能总是用同一个顾客替换,因为你有 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;
          
          ?>
          

          【讨论】:

          • 您仍将所有 3 个 div 设置为相同的值,因为您尚未在正则表达式中命名 data-tag-id。
          • 道歉 - 我没有注意到您已将其分解为不同的行,然后分别在每一行上运行正则表达式。所以你是对的,它适用于这些确切的数据。但是,如果您在其中一个 div 前面引入诸如空行之类的简单内容会发生什么 - 没有什么可以使 $i 和 $rowNode 保持同步...
          • 在这种情况下这不是最好的解决方案,但我只是做他需要的事情
          【解决方案6】:

          不要使用 RegEx 解析/更改 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();
          

          输出(格式化):

          <!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 作为 XHTML 导入/导出到 DOMDocument。

          【讨论】:

            猜你喜欢
            • 2020-11-09
            • 1970-01-01
            • 2022-12-08
            • 1970-01-01
            • 2020-12-24
            • 2015-07-22
            • 2013-12-07
            • 2017-12-16
            • 1970-01-01
            相关资源
            最近更新 更多