用特定PHP代码中的XMLReader替换解析函数

时间:2014-06-06 14:26:49

标签: php xml parsing

我正在尝试利用PHP脚本将大型XML文件(大约450 MB)解析为MYSQL数据库,将某些结构和定义解析为包含的XML元素。问题是原始脚本使用 file_get_contents SimpleXMLElement 来完成它,但服务器执行的corn作业由于XML文件的大小而停止。我没有PHP专家,因此我购买了这个XMLSplit软件并将XML分成17个独立的XML文件,每个文件大小为30 MB,使用相同的脚本逐个解析它们。但是,输出数据库丢失了很多输入,如果没有自动划分并逐个解析,我怀疑这是否与原始文件的输出相同。

因此,我决定使用XMLReader和这个确切的PHP脚本来解析这个大的XML文件,但到目前为止,我无法简单地替换解析代码并保持其他功能不变。

我包括下面的脚本,如果有人帮我这样做,我真的很感激。

<?php
set_time_limit(0);
ini_set('memory_limit', '1024M');

include_once('../db.php');
include_once(DOC_ROOT.'/include/func.php');

mysql_query("TRUNCATE screenshots_list");
mysql_query("TRUNCATE pages");
mysql_query("TRUNCATE page_screenshots");


$xmlstr = file_get_contents('t_info.xml');
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->template as $item)

{
//print_r($item);
$sql = sprintf("REPLACE INTO templates SET id = %d, state = %d, price = %d,           exc_price = %d, inserted_date = '%s', update_date = '%s', downloads = %d, type_id = %d, type_name = '%s', is_flash = %d, is_adult = %d, width = '%s', author_id = %d, author_nick = '%s', package_id = %d, is_full_site = %d, is_real_size = %d, keywords = '%s', sources = '%s', description = '%s', software_required = '%s'", $item->id, $item->state, $item->price, $item->exc_price, $item->inserted_date, $item->update_date, $item->downloads, $item->template_type->type_id, $item->template_type->type_name, $item->is_flash, $item->is_adult, $item->width, $item->author->author_id, $item->author->author_nick, $item->package->package_id, $item->is_full_site, $item->is_real_size, $item->keywords, $item->sources, $item->description, $item->software_required);
//echo '<br>'.$sql;
mysql_query($sql);
//print_r($item->screenshots_list->screenshot);
foreach ($item->screenshots_list->screenshot as $scr) {
    $main = (!empty($scr->main_preview)) ? 1 : 0;
    $small = (!empty($scr->small_preview)) ? 1 : 0;
    insert_data($item->id, 'screenshots_list', 0, $scr->uri, $scr->filemtime, $main, $small);       
}
foreach ($item->styles->style as $st) {
    insert_data($item->id, 'styles', $st->style_id, $st->style_name);       
}
foreach ($item->categories->category as $cat) {
    insert_data($item->id, 'categories', $cat->category_id, $cat->category_name);       
}
foreach ($item->sources_available_list->source as $so) {
    insert_data($item->id, 'sources_available_list', $so->source_id, '');       
}
foreach ($item->software_required_list->software as $soft) {
    insert_data($item->id, 'software_required_list', $soft->software_id, '');       
}
//print_r($item->pages->page);
if (!empty($item->pages->page)) {
    foreach ($item->pages->page as $p) {
        mysql_query(sprintf("REPLACE INTO pages SET tpl_id = %d, name = '%s', id = NULL ", $item->id, $p->name));
        $page_id = mysql_insert_id();
        if (!empty($p->screenshots->scr)) {
            foreach ($p->screenshots->scr as $psc) {
                $href = (!empty($psc->href)) ? (string)$psc->href : '';
                mysql_query(sprintf("REPLACE INTO page_screenshots SET page_id = %d, description = '%s', uri = '%s', scr_type_id = %d, width = %d, height = %d, href = '%s'", $page_id, $psc->description, $psc->uri, $psc->scr_type_id, $psc->width, $psc->height, $href));
            }
        }
    }
}}?>

要突出显示相关代码行,这是我尝试使用XMLReader方法替换而不影响其余脚本功能的部分:

   $xmlstr = file_get_contents('t_info.xml');
   $xml = new SimpleXMLElement($xmlstr);
   foreach ($xml->template as $item) {

我非常感谢您的解决方案...

1 个答案:

答案 0 :(得分:0)

可以将XML阅读器位置扩展为DOMElement。此元素与DOMDocument无关,因此无法直接将其转换为SimpleXMLElement,但可以将其导入DOMDocument。

$xml = <<<'XML'
<templates>
  <template>
     <styles>
        <style>TEST</style>
     </styles>
  </template>
</templates>
XML;

$reader = new XMLReader;
$reader->open('data://text/xml;base64,'.base64_encode($xml));

$dom = new DOMDocument;

// look for the first template element
while ($reader->read() && $reader->localName !== 'template') {
  continue;
}

// while you have an template element
while ($reader->localName === 'template') {
  // convert to SimpleXMLElement
  $element = simplexml_import_dom(
    // expand to a DOMElement in the prepared document object
    $reader->expand($dom)
  );
  var_dump(
    $element 
  );
  // move to the next template sibling
  $reader->next('template');
}

输出:

object(SimpleXMLElement)#3 (1) {
  ["styles"]=>
  object(SimpleXMLElement)#4 (1) {
    ["style"]=>
    string(4) "TEST"
  }
}

我通常使用DOM + Xpath并且不将其转换为SimpleXML,但这种方法应该可以很好地解决您的问题。