PHP DomDocument HTML 操作

3
我有以下HTML代码。
<div id="container">
    <div id="current">Current Div</div>
</div>

使用PHP中的DomDocument,在具有id为“current”的div之前添加一个额外的div。
<div id="container">
    <div id="new">New Div</div>
    <div id="current">Current Div</div>
</div>

当我使用以下代码时,它似乎将div添加到id为“current”的div内部,但是在此div的内容之前。有人能告诉我这是为什么以及如何使结果与上面的HTML相同吗?(请参见下面的HTML问题) 当前PHP:
$doc = new DOMDocument();
$doc->formatOutput = true;

$doc->loadHTMLFile('index.html');

$head = $doc->getElementById('current');
$base = $doc->createElement('div', 'New Div');
$base->setAttribute('id', 'new');
echo $doc->saveHTML();

HTML问题

<div id="container">
    <div id="current">
        <div id="new">New Div</div>
        Current Div
    </div>
</div>

EDIT:

PHP

$doc = new DOMDocument();
$doc->formatOutput = true;

$doc->loadHTMLFile('index.html');
$container = $doc->getElementById('container');
$current = $doc->getElementById('username');
$new = $doc->createElement('div', 'New Div');

$new->setAttribute('id', 'new');
$container->insertBefore($new, $current);
echo $doc->saveHTML();

HTML

<div id="container">
    <form method="post" action="">
        <input type="text" name="username" id="username" />
    </form>
</div>

错误:

Fatal error: Uncaught exception 'DOMException' with message 'Not Found Error' 
in index.php:55 Stack trace: #0 index.php(55): 
DOMNode->insertBefore(Object(DOMElement), Object(DOMElement))
1个回答

3
您可以使用 DOMNode::insertBefore():
<?php

$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadHTMLFile('index.html');

$container = $doc->getElementById('container');
$current = $doc->getElementById('current');
$new = $doc->createElement('div', 'New Div');

$new->setAttribute('id', 'new');
$container->insertBefore($new, $current);

var_dump($doc->saveHTML());

这将产生:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
    <body>
        <div id="container">
            <div id="new">New Div</div>
            <div id="current">Current Div</div>
        </div>
    </body>
</html>

希望这可以帮到你 :)
编辑:
关于你报告的问题...我看到了问题: input#username 不是 div#container 的直接子元素,它是 form 的直接子元素。因此,您需要将 form 元素作为 DOMNode 对象获取,而不是其父级 div#container。最简单的方法是为 form 添加一个 id,并执行以下操作:
$form = $doc->getElementById('form');
$username = $doc->getElementById('username');
$username->setAttribute('value', 'Enter username!');

var_dump($doc->saveHTML());

这是基于以下HTML的。请注意, form 元素具有一个ID:

这是基于以下HTML的。请注意,form元素具有一个ID:

<div id="container">
    <form id="form" method="post" action="">
        <input type="text" name="username" id="username">
    </form>
</div>

如果因为某些原因无法向表单元素添加 ID,您可以像这样从 div#container 遍历:
// find div#container element
$container = $doc->getElementBy('id');
// find all form elements that are children of div#container
$forms = $container->getElementsByTagName('form');

if (0 !== $forms->length) {
   $form = $forms->item(0);
}

// etc.

编辑 #2

我差点忘了XPath... 如果你想更简洁/冒险,你可以使用DOMXPath::query()来查找DOM节点:

$xpath = new DOMXPath($doc);
$form  = $xpath->query('body/div[@id="container"]/form')->item(0);
$input = $xpath->query('body//input[@id="username"]')->item(0);

XPath查询语法十分晦涩但功能强大,我并不是专家,无法保证这些查询的效率。另外,您可能需要添加错误检查 - query方法返回一个DOMNodeList,该列表具有length属性。
最后值得注意的是,DOMDocument会在您的HTML片段中添加DOCTYPE、html和body标签;这就是为什么XPath查询从body开始遍历的原因。

为什么脚本在引用输入文本框的 ID 而不是带有 ID“current”的 div 时会中断?- 有什么区别? - Richy
嗨Richy。它出了问题?有趣...你收到了特定的错误吗?以下对我有效: `$input = $doc->createElement('input'); $input->setAttribute('type', 'text'); $input->setAttribute('id', 'foo'); $input->setAttribute('value', 'bar');$container->insertBefore($input, $current);` - Darragh Enright
我已经更新了原始帖子,包括更多细节 :) - Richy
你知道吗...我觉得我误读了你的评论 - input 元素是否已经存在于 index.html 中?如果是这样,请您发布导致问题的 PHP 代码行。 - Darragh Enright
没问题,HTML 已经包含了输入元素。我已经在原帖中粘贴了 PHP、HTML 和错误信息。它好像不喜欢 insertBefore 方法? - Richy
如果您的问题得到解决,请不要忘记将问题标记为已回答 :) - Darragh Enright

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接