gpt4 book ai didi

PHP 和 XML - 删除节点

转载 作者:可可西里 更新时间:2023-11-01 01:06:35 24 4
gpt4 key购买 nike

我创建了一个 PHP 脚本,它通过 AJAX 从 XML 文档构建一个表。例如:

<bookstore>
<book>
<title>Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>

将创建一个包含标题、作者、年份和价格列以及一个额外的删除列的表。在解析 XML 时,我已将 tr id 设置为上述情况中当前 XML 元素(0 和 1)的 tr id。

当我点击删除时,我用我要删除的行的 ID 发出了一个 AJAX 请求。删除脚本正在毫无问题地接收当前行号,但在尝试删除它时我遇到了奇怪的结果。我正在尝试的当前代码如下(取自 http://quest4knowledge.wordpress.com/2010/09/04/php-xml-create-add-edit-modify-using-dom-simplexml-xpath/ 7.2)

if (isset($_POST['rowNumber'])) {

$rowNumber = $_POST['rowNumber'];
$file = $_POST['file'];

$dom = new DOMDocument();
$dom->load("../XML/".$file);
$xml = $dom->documentElement;
//PROBLEM HERE
$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item($rowNumber));

$handle = fopen("../XML/".$file, 'w');
fwrite($handle, $dom->saveXML());

}

我在页面加载时构建表,然后在每次删除时构建表。问题是错误的行被删除了,我不知道为什么。

其他测试...

在 50% 的点击时删除第一个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(0));

总是删除第一个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(1));

在 50% 的点击时删除第二个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(2));

总是删除第二个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(3));

在 50% 的点击中删除第三个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(4));

始终删除第三个节点:

$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item(5));

添加了我的 AJAX 代码

$('#generatedTable a.delete').live('click', function (e) {
e.preventDefault();

//TABLE ROW ID TO BE DELETED. CAN ALERT THIS FINE.
var trID = $(this).closest('tr').attr('id');

$.ajax({
url: "functions/xmlDelete.php",
type: "POST",
dataType: "json",
data: "rowNumber="+ trID + "&fileName=" + fileName,
success: function(data) {

$.ajax({
url: "functions/xmlParser.php",
type: "POST",
dataType: "json",
data: "fileName="+ fileName,
success: function(data) {

$('#xmlTable').html(data.table);
$('#xmlTable').fadeIn('fast');

oTable = $('#generatedTable').dataTable({
"bJQueryUI": true,
"bPaginate": false,
"bLengthChange": false,
"bFilter": false,
"bSort": false,
"bInfo": true
});

}
});

}
});
} );

这是我的表格行的样子,我可以毫无问题地提醒 trID。

<tr id="0" class="odd">
<td id="0">1999 Grammy Nominees</td>
<td id="1">Many</td>
<td id="2">USA</td>
<td id="3">Grammy</td>
<td id="4">10.20</td>
<td id="5">1999</td>
<td align="center"><a class="edit" href="">Edit</a></td>
<td align="center"><a class="delete" href="">Delete</a></td>
</tr>

任何人都可以帮助解释我在这里看到的东西。谢谢!

最佳答案

你没有考虑到 childNodes()包括所有节点,而不仅仅是元素。

对于您提供的 xml 文档,$dom->documentElement->childNodes->item(0)<bookstore> 末尾之间的空格和<book>的开头,不是第一个 <book>节点。

现在你知道为什么 DOM 如此令人讨厌了。

我建议您使用 DOMXPathSimpleXML而不是遍历 childNodes收集元素索引。

DOMXPath解决方案

if (isset($_POST['rowNumber'], $_POST['file']) and ctype_digit($_POST['rowNumber'])) {
$rowNumber = $_POST['rowNumber'];
$file = '../XML/'.$_POST['file'];

$dom = new DOMDocument();
$dom->load($file);

$root = $dom->documentElement;

$xp = new DOMXPath($dom);
$books = $xp->query('*', $root);
if ($books->item($rowNumber)) {
$root->removeChild($books->item($rowNumber));
// Note that "$root->childNodes->item(0)->parentNode" is completely unnecessary.
// You already have the parent node ($root), so just use it directly!
} else {
echo "Row does not exist";
}

$dom->save($file);
}

SimpleXML解决方案

if (isset($_POST['rowNumber'], $_POST['file']) and ctype_digit($_POST['rowNumber'])) {
$rowNumber = (int) $_POST['rowNumber']; // casting to int is necessary!!
$file = '../XML/'.$_POST['file'];

$sxe = simplexml_load_file($file);
unset($sxe->book[$rowNumber]);

// or, if you don't want to make element name assumptions:
// $children = $sxe->children();
// unset($children[$rowNumber]);

$sxe->asXML($file);
}

问题

但是,您的整个方法存在两个严重问题。

  1. 您正在通过 file 接受不受信任的输入发布变量。用户无需读取和写入驱动器上的任何 XML 文件。您应该有一个预定义的有效列表 file $_POST['file'] 的值必须匹配才能处理请求。

  2. 您没有考虑并发性。这表现在两个方面:

    1. 如果两个用户同时编辑,其中一个删除了第 0 本书,那么当第二个用户删除第 0 本书时,他将删除一本与他想要的不同的书,即在他看来成为第一本书!对此的解决方案是每本书都需要一个明确的、唯一的标识符,您可以在 XML 文件和 html 界面中使用该标识符。您不能使用索引编号来标识节点。
    2. 您对 XML 文件的读写不是原子的,也不使用任何文件锁定。因此,当另一个 PHP 进程正在写入文件时,某人可能正在读取 XML,从而给读者一个不完整的 XML 文件。您必须执行原子写入(在 *nix 系统上,写入唯一的临时文件,然后将 link() 写入真实文件名),或者您必须使用 flock() 打开文件。或其他一些锁定机制。

因为管理并发读写(尤其是快速方式)非常困难,我建议您放弃这种文件即数据库的方法,改用真实的数据库。

(顺便说一下,您的 HTML 无效。id 属性在文档中必须是唯一的,但您有两个 id="0" 。)

关于PHP 和 XML - 删除节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9456482/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com