我看到一些我无法调试的奇怪行为。该代码来自 WordPress 短代码变体的简单实现。
代码循环遍历 DOMNodeList(自定义 html 标签)并调用另一个函数依次处理每个 DOMElement。该函数将 DOMElement 替换为另一个 DOMElement,并返回结果文本。
第一次通过该循环和函数调用,一切都完全按预期工作。然而,第二次,对 DOMElement->replaceWith() 的调用失败,没有抛出任何异常。我已经检查过每个循环和调用都在不同的 DOMElement(标签)上工作。我真的很困惑。
任何想法都非常感激。简化的代码段如下:
编辑:这是一个更完整的代码示例,试图避免在这里粘贴太多我的意大利面条。 ;-) 编辑:添加了一点以使复制更容易
// for demonstration: this comes from the database
$content = '
<div>
<p>This is a test ...</p>
<sc-snippet id="Test Snippet 1"/>
<sc-snippet id="test-snippet-2"/>
</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());
}
C3roe 让我走上了正轨,问题是 getElementsByTagName() 是“实时”的。我按照他们的建议以相反的顺序浏览元素,这似乎已经成功了。
谢谢C3roe!!!