我创建了一个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>
任何人都可以帮助解释我在这里看到的内容。谢谢!
答案 0 :(得分:2)
如果我理解您正确链接的文档,
$library->childNodes->item(0)->parentNode
简单地将DOMDocument转换为DOMElement是一种复杂且恼人的方式。您将在更多示例中发现该模式。
现在我们有了一个DOMElement,我们可以在它上面调用removeChild(),它会被传递给DOMElement。这个元素是
$library->childNodes->item(1)
表示第二个元素。
因此,您的代码可能应该如下所示:
$xml->childNodes->item(0)->parentNode->removeChild($xml->childNodes->item($rowNumber));
鉴于$ rowNumber是从0开始的。
答案 1 :(得分:2)
您没有考虑childNodes()
包含所有节点,而不仅仅是元素。
对于您提供的xml文档,$dom->documentElement->childNodes->item(0)
是<bookstore>
末尾与<book>
开头之间的空白,不是第一个<book>
1}} node。
现在你知道为什么DOM太刺激了。
我建议您使用DOMXPath
或SimpleXML
而不是循环遍历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);
}
但是,整个方法存在两个严重问题。
您通过file
帖子变量接受不受信任的输入。用户无需读写驱动器上的任何XML文件。在处理请求之前,您应该有file
必须匹配的有效$_POST['file']
值的预定义列表。
您不考虑并发性。这表现在两个方面:
因为管理并发读写(特别是以快速方式)是如此困难,所以我建议你放弃这种文件作为数据库的方法,而是使用真正的数据库。
(顺便提一下,您的HTML无效。id
属性在文档中必须是唯一的,但您有两个id="0"
。)