php DOMElement->replaceWith() 的奇怪问题

问题描述 投票:0回答:1

我看到一些我无法调试的奇怪行为。该代码来自 WordPress 短代码变体的简单实现。

代码循环遍历 DOMNodeList(自定义 html 标签)并调用另一个函数依次处理每个 DOMElement。该函数将 DOMElement 替换为另一个 DOMElement,并返回结果文本。

第一次通过该循环和函数调用,一切都完全按预期工作。然而,第二次,对 DOMElement->replaceWith() 的调用失败,没有抛出任何异常。我已经检查过每个循环和调用都在不同的 DOMElement(标签)上工作。我真的很困惑。

任何想法都非常感激。简化的代码段如下:

编辑:这是一个更完整的代码示例,试图避免在这里粘贴太多我的意大利面条。 ;-) 编辑:添加了一点以使复制更容易




// for demonstration: this comes from the database
$content = '
<div>
  <p>This is a test ...</p>
  &lt;sc-snippet id="Test Snippet 1"/&gt;
  &lt;sc-snippet id="test-snippet-2"/&gt;
</div>
';

function processContent($content)
{
  $scodes = loadScodes();
  $snames = array_keys($scodes);  
  $dom = new DOMDocument('1.0', 'UTF-8');
  $dom->loadHTML(htmlspecialchars_decode($content)); // decode the entities in custom tags
  foreach($snames as $sname)
  {
    $scTags = $dom->getElementsByTagName($sname);
    foreach($scTags as $tag)
    {
      $parsed = parseScodeTag($tag, $scodes[$sname]);
      $scode = $parsed['scode'];
      $handler = $scodes[$scode]['handler'];
      $content = $handler($parsed['attrs'], $dom, $tag);
    } // end foreach found tag
  } // end foreach known scode
  return(html_entity_decode($content));  // this should be the HTML segment with tags replaced by snippets

} // end processContent()

function loadScodes()
{
  //$config = config(SCODE_CONFIG);
  //$scodes = $config->get(SCODE_SCODES);
  // for demonstration:
  $scodes = array(
    'sc-snippet' => array(
      'handler' => 'handleSnippet',
      'attrs' => array('id'),
    ),
  );
  return($scodes);
}

// for demonstration, snippets are stored in the database and handled in a different module
function loadSnippet($id)
{
  $snippets = array(
    'Test Snippet 1' => '<p>This is a test snippet 1</p>',
    'test-snippet-2' => '<p>This is a test snippet 2</p>',
  );
  return($snippets[$id]);
}


function parseScodeTag($tag, $scode)
{ 
  $parsed = array();
  $parsed['scode'] = $tag->nodeName;
  $parsed['handler'] = $scode['handler'];
  $scodeAttrs = array();
  if ( isset($scode['attrs']) && count($scode['attrs']) > 0 )
  {
    foreach ($scode['attrs'] as $attr)
    {
      $attrVal = $tag->getAttribute($attr);
      $scodeAttrs[$attr] = $attrVal;
    } 
  }
  $parsed['attrs'] = $scodeAttrs;
  return($parsed);
}

function handleSnippet($attrs, $dom, $tag)
{ // return a block of html
  // check for attributes
  if (!isset($attrs['id']))
  {
    return($dom->saveHTML());
  }
  $snip = loadSnippet($attrs['id']);

  $e = $dom->createElement('div', $snip);
  try {
    $tag->replaceWith($e);
  } catch(Exception $e) { // never get here
    _dd('CAUGHT', false);
  } finally { // correction, do not get here on the second time through
    _dd('FINALLY', false);
  }
  return($dom->saveHTML());
}

php dom domdocument
1个回答
0
投票

C3roe 让我走上了正轨,问题是 getElementsByTagName() 是“实时”的。我按照他们的建议以相反的顺序浏览元素,这似乎已经成功了。

谢谢C3roe!!!

© www.soinside.com 2019 - 2024. All rights reserved.