Ram*_*i.Q 5 php xml xmlwriter xmlreader data-manipulation
我有一个非常大的XML文件(数百万条记录).由于速度和内存限制,我打算使用XMLReader/ XMLWriter.
我需要读取文件,获取一条记录,更改其属性,最后再次保存XML.
为了测试,我创建了一个XML文件,并使用以下行将一些记录写入其中:
$doc = new XMLWriter();
$doc->openURI($xmlFile);
$doc->startDocument('1.0','UTF-8');
$doc->setIndent(4);
$doc->startElement('DBOS');
for($r=0;$r<10; $r++){
$doc->startElement('ITEMS');
for($i=0;$i<5; $i++){
$doc->startElement('ITEM');
$doc->writeAttribute('id', $r.'-'.$i);
$doc->endElement();
}
$doc->endElement();
}
$doc->endElement();
$doc->endDocument();
$doc->flush();
Run Code Online (Sandbox Code Playgroud)
我用这个再读一遍:
$reader = new XMLReader();
if (!$reader->open($xmlFile)){
die("Failed to open 'data.xml'");
}
while($reader->read()){
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'ITEMS') {
$node = $reader->expand();
$items = $node->childNodes;
foreach ($items as $ik => $itm ){
print $itm->textContent.'<br/>';
// how to change the ID Attribute of a Node (DomNode) and save changes to the original XML File
}
break;
}
}
$reader->close();
Run Code Online (Sandbox Code Playgroud)
我的问题:如何更改a的id属性DomNode并再次使用XMLWriter将更改保存到原始XML文件?
如何更改DomNode的id属性并再次使用XMLWriter保存对原始XML文件的更改?
这不起作用.如果您使用XMLReader和XMLWriter同时对同一文件进行操作,则该文件将被编写器截断,并且读取器将吐出错误并停止工作.
但是,您可以对不同的文件进行操作.
所以你可以做的是使用XMLReader来读取文档,当你对它进行操作时,使用XMLWriter根据你读过的和偶尔修改的内容写入另一个文档.完成后,您可以将新写入的文件重命名为旧文件名.
对于一个XML文档(缩写为示例,XMLReader和XMLWriter自然而然地使用非常大的文档),像这样在你的问题之后建模了一下:
<DBOS>
<ITEMS>
<ITEM>item #1</ITEM>
<ITEM>item #2</ITEM>
<ITEM>item #3</ITEM>
</ITEMS>
<ITEMS>
<ITEM>item #4</ITEM>
<ITEM>item #5</ITEM>
</ITEMS>
</DBOS>
Run Code Online (Sandbox Code Playgroud)
一个有效的代码示例是:
<?php
/*
* This file is part of the XMLReaderIterator package.
*
* Copyright (C) 2012, 2014 hakre <http://hakre.wordpress.com>
*
* Example: Write XML with XMLWriter while reading from XMLReader with XMLWriterIteration
*/
require('xmlreader-iterators.php'); // require XMLReaderIterator library
$xmlInputFile = 'data/dobs-items.xml';
$xmlOutputFile = 'php://output';
$reader = new XMLReader();
$reader->open($xmlInputFile);
$writer = new XMLWriter();
$writer->openUri($xmlOutputFile);
$iterator = new XMLWritingIteration($writer, $reader);
$writer->startDocument();
$itemsCount = 0;
$itemCount = 0;
foreach ($iterator as $node) {
$isElement = $node->nodeType === XMLReader::ELEMENT;
if ($isElement && $node->name === 'ITEMS') {
// increase counter for <ITEMS> elements and reset <ITEM> counter
$itemsCount++;
$itemCount = 0;
}
if ($isElement && $node->name === 'ITEM') {
// increase <ITEM> counter and insert "id" attribute
$itemCount++;
$writer->startElement($node->name);
$writer->writeAttribute('id', $itemsCount . "-" . $itemCount);
if ($node->isEmptyElement) {
$writer->endElement();
}
} else {
// handle everything else
$iterator->write();
}
}
$writer->endDocument();
Run Code Online (Sandbox Code Playgroud)
然后输出(标准输出示例,可以使用任何有效的PHP文件名):
<?xml version="1.0"?>
<DBOS>
<ITEMS>
<ITEM id="1-1">item #1</ITEM>
<ITEM id="1-2">item #2</ITEM>
<ITEM id="1-3">item #3</ITEM>
</ITEMS>
<ITEMS>
<ITEM id="2-1">item #4</ITEM>
<ITEM id="2-2">item #5</ITEM>
</ITEMS>
</DBOS>
Run Code Online (Sandbox Code Playgroud)
如此示例所示,id属性是根据不同计数器变量的编号添加的.
该XMLWritingIteration让一切变得简单,因为它与所有其他节点,并感谢案件涉及$iterator->write().
示例和代码是XMLReaderIterator包的一部分.还有另一个例子是基于XMLReader创建DOMDocument,它是"如何区分DOMDocument中的空元素和空大小字符串?"的答案的一部分..