使用XMLReader读取子节点

时间:2013-06-23 16:25:11

标签: php xml simplexml xmlreader

我正在尝试编写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文档非常缺乏,并且通常很难找到清晰简洁的详细指南。

2 个答案:

答案 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;
}