我正在尝试编写XMLReader / SimpleXML混合函数来读取非常大的(700MB)XML文件。 XML采用以下格式:
<Items>
<Item>
<ItemKey>ABCDEF123</ItemKey>
<Name>
<English>An Item Name</English>
<German>An Item Name In German</German>
<French>An Item Name In French</French>
</Name>
<Description>
<English>An Item Description</English>
<German>An Item Description In German</German>
<French>An Item Description In French</French>
</Description>
</Item>
<Item>
<ItemKey>GHIJKL456</ItemKey>
<Name>
<English>Another Item Name</English>
<German>Another Item Name In German</German>
<French>Another Item Name In French</French>
</Name>
<Description>
<English>Another Item Description</English>
<German>Another Item Description In German</German>
<French>Another Item Description In French</French>
</Description>
</Item>
</Items>
到目前为止我写的代码是这样做的:
$xml = new XMLReader();
if(!$xml->open('testitems.xml')){
die('Failed to open file!');
} else {
echo 'File opened';
}
$items = array();
while ($xml->read()){
if($xml->nodeType == XMLReader::ELEMENT){
if ($xml->name == 'Item'){
$item = array();
}
if ($xml->name == 'ItemKey'){
$xml->read();
$item['itemKey'] = $xml->value;
}
if ($xml->name == 'Name'){
$sxml = new SimpleXMLElement($xml->readOuterXml());
$englishName = $sxml->English;
$item['englishName'] = $englishName;
}
}
if($xml->nodeType == XMLReader::END_ELEMENT){
if ($xml->name == 'Item'){
$items[] = $item;
}
}
}
var_dump($items);
$xml->close();
但是,当ItemKey节点值被插入到数组中时,英文名称不是,我似乎无法正确访问此节点。我只是将XMLReader用于所有内容,但是因为我的谷歌搜索中出现了英语节点(一个用于名称,另一个用于描述),因此到目前为止,SimpleXML似乎是前进的方向,但目前尚无欢乐。
有什么建议吗?有什么好的指南?与许多其他PHP功能相比,php.net上的XMLReader文档非常缺乏,并且通常很难找到清晰简洁的详细指南。
答案 0 :(得分:4)
如果您仍然可以构建该数组,那么您的XML文件可能不是那么大:)。例如,尝试使用simplexml加载整个文件,您可能会惊讶于它不会消耗那么多内存。
无论如何,如果你仍然想要使用XMLReader,我经常建议我的XMLReader Iterator library能够遍历XMLReader
以访问元素,子项并执行诸如将片段转换为{{1}之类的内容}第
以下是与上述示例几乎相同的示例:
SimpleXMLElement
在演示数据上运行时,生成的require('xmlreader-iterators.php'); // https://github.com/hakre/XMLReaderIterator/tree/master/build/include
$xmlFile = "xmlreader-17262798.xml";
$reader = new XMLReader();
$reader->open($xmlFile);
/* @var $itemIterator XMLReaderNode[] */
$itemIterator = new XMLElementIterator($reader, 'Item');
$items = array();
foreach ($itemIterator as $item) {
$xml = $item->asSimpleXML();
$items[] = array(
'itemKey' => (string)$xml->ItemKey,
'englishName' => (string)$xml->Name->English,
);
}
数组为:
$items
从技术上讲,您不需要使用该库,它只能在 Array
(
[0] => Array
(
[itemKey] => ABCDEF123
[englishName] => An Item Name
)
[1] => Array
(
[itemKey] => GHIJKL456
[englishName] => Another Item Name
)
)
上运行,因此它不会改变XMLReader
的工作方式。它是一个附加组件。
为什么它在您的特定情况下无法正常工作很难说,您的代码在我的计算机上运行得非常完美:
XMLReader
当Array
(
[0] => Array
(
[itemKey] => ABCDEF123
[englishName] => SimpleXMLElement Object
(
[0] => An Item Name
)
)
[1] => Array
(
[itemKey] => GHIJKL456
[englishName] => SimpleXMLElement Object
(
[0] => Another Item Name
)
)
)
(您的代码)的print_r
输出显示时, englishName 键设置为simplexml元素。您可能想要将这些转换为字符串,就像我在我的示例中所做的那样(这两个$items
部分),以便在那里使用字符串而不是SimpleXMLElements,这可能是您的问题。如果没有,请检查您的libxml版本:
(string)
并将其报告回来(即var_dump(LIBXML_DOTTED_VERSION); # string(5) "2.7.8"
所基于的库)。同时调试SimpleXMLElement(XMLReader
),以便检查已加载的XML。
图书馆我建议顺便说一句。如果您想快速尝试,也可以使用a single include file。
上次我建议图书馆在:
编辑:另一个没有库的混合版本显示var_dump($sxml->asXML());
的使用,当你在同名的兄弟姐妹上迭代时,这个版本非常有用:next()
:
<Item>
答案 1 :(得分:-1)
没关系,明白了。对于那些陷入困境的人:
$xml = new XMLReader();
if(!$xml->open('Items.xml')){
die('Failed to open file!');
} else {
echo 'File opened';
}
$items = array();
while ($xml->read() && $xml->name !== "Item");
while ($xml->name === "Item") {
$item = array();
$node = new SimpleXMLElement($xml->readOuterXML());
$item['itemkey'] = $node->ItemKey;
$item['englishName'] = $node->Name->English;
$item['englishDesc'] = $node->Description->English;
$items[] = $item;
}