4

PHP と XMLReader を使用して非常に大きな XML ファイルを解析しようとしましたが、探している結果が得られないようです。基本的に、私は大量の情報を検索しています。特定の郵便番号が含まれている場合は、そのビットの XML を返すか、その郵便番号が見つかるまで検索を続けます。基本的に、この大きなファイルをいくつかの小さなチャンクに分割するので、数千または数百万の情報グループを調べる代わりに、おそらく 10 または 20 になるでしょう。

これは、私がしたいことを含むXMLの一部です

//search through xml
<lineups country="USA">
//cache TX02217 as a variable
 <headend headendId="TX02217">
//cache Grande Gables at The Terrace as a variable
  <name>Grande Gables at The Terrace</name>
//cache Grande Communications as a variable
  <mso msoId="17541">Grande Communications</mso>
  <marketIds>
   <marketId type="DMA">635</marketId>
  </marketIds>
//check to see if any of the postal codes are equal to $pc variable that will be set in the php
  <postalCodes>
   <postalCode>11111</postalCode>
   <postalCode>22222</postalCode>
   <postalCode>33333</postalCode>
   <postalCode>78746</postalCode>
  </postalCodes>
//cache Austin to a variable
  <location>Austin</location>
  <lineup>
//cache all prgSvcID's to an array i.e. 20014, 10722
   <station prgSvcId="20014">
//cache all channels to an array i.e. 002, 003  
    <chan effDate="2006-01-16" tier="1">002</chan>
   </station>
   <station prgSvcId="10722">
    <chan effDate="2006-01-16" tier="1">003</chan>
   </station>
  </lineup>
  <areasServed>
   <area>
//cache community to a variable $community   
    <community>Thorndale</community>
    <county code="45331" size="D">Milam</county>
//cache state to a variable i.e. TX
    <state>TX</state>
   </area>
   <area>
    <community>Thrall</community>
    <county code="45491" size="B">Williamson</county>
    <state>TX</state>
   </area>
  </areasServed>
 </headend>

//if any of the postal codes matched $pc 
//echo back the xml from <headend> to </headend>

//if none of the postal codes matched $pc
//clear variables and move to next <headend>

 <headend>
 etc
 etc
 etc
 </headend>
 <headend>
 etc
 etc
 etc
 </headend>
 <headend>
 etc
 etc
 etc
 </headend> 
</lineups>

PHP:

<?php
$pc = "78746";
$xmlfile="myFile.xml";
$reader = new XMLReader();
$reader->open($xmlfile); 

while ($reader->read()) { 
//search to see if groups contain $pc and echo info
}

これを必要以上に難しくしていることはわかっていますが、そのような大きなファイルを操作しようとすると少し圧倒されます. どんな助けでも大歓迎です。

4

2 に答える 2

7

柔軟性を高めるために、XMLReader私は通常、オブジェクトを操作して必要なステップを提供できるイテレータをXMLReader自分で作成します。

これは、すべてのノードに対する単純な反復から始まり、オプションで特定の名前を持つ要素に対する反復まで続きます。XMLElementIteratorリーダーと要素名をパラメーターとして受け取る最後のものを呼び出しましょう。

あなたのシナリオでは、要素のみを取得して、現在の要素の a を返すイテレータを作成しますSimpleXMLElement<headend>

require('xmlreader-iterators.php'); // https://gist.github.com/hakre/5147685

class HeadendIterator extends XMLElementIterator {
    const ELEMENT_NAME = 'headend';

    public function __construct(XMLReader $reader) {
        parent::__construct($reader, self::ELEMENT_NAME);
    }

    /**
     * @return SimpleXMLElement
     */
    public function current() {
        return simplexml_load_string($this->reader->readOuterXml());
    }
}

このイテレータを装備すれば、残りの作業は簡単です。最初に 10 ギガバイトのファイルをロードします。

$pc      = "78746";

$xmlfile = '../data/lineups.xml';
$reader  = new XMLReader();
$reader->open($xmlfile);

次に、<headend>要素に情報が含まれているかどうかを確認し、含まれている場合は、データ/XML を表示します。

foreach (new HeadendIterator($reader) as $headend) {
    /* @var $headend SimpleXMLElement */
    if (!$headend->xpath("/*/postalCodes/postalCode[. = '$pc']")) {
        continue;
    }

    echo 'Found, name: ', $headend->name, "\n";
    echo "==========================================\n";
    $headend->asXML('php://stdout');
}

これは文字通り、あなたが達成しようとしていることです: 関心のある要素が見つかるまで、大きなドキュメント (メモリに優しい) を反復処理します。次に、具体的な要素を処理しますが、それは XML のみです。XMLReader::readOuterXml()ここでは素晴らしいツールです。

出力例:

Found, name: Grande Gables at The Terrace
==========================================
<?xml version="1.0"?>
<headend headendId="TX02217">
        <name>Grande Gables at The Terrace</name>
        <mso msoId="17541">Grande Communications</mso>
        <marketIds>
            <marketId type="DMA">635</marketId>
        </marketIds>
        <postalCodes>
            <postalCode>11111</postalCode>
            <postalCode>22222</postalCode>
            <postalCode>33333</postalCode>
            <postalCode>78746</postalCode>
        </postalCodes>
        <location>Austin</location>
        <lineup>
            <station prgSvcId="20014">
                <chan effDate="2006-01-16" tier="1">002</chan>
            </station>
            <station prgSvcId="10722">
                <chan effDate="2006-01-16" tier="1">003</chan>
            </station>
        </lineup>
        <areasServed>
            <area>
                <community>Thorndale</community>
                <county code="45331" size="D">Milam</county>
                <state>TX</state>
            </area>
            <area>
                <community>Thrall</community>
                <county code="45491" size="B">Williamson</county>
                <state>TX</state>
            </area>
        </areasServed>
    </headend>
于 2013-03-12T01:26:33.917 に答える
0

編集:ああ、親チャンクを返したいですか?一瞬。

すべての郵便番号を配列に取り出す例を次に示します。

http://codepad.org/kHss4MdV

<?php

$string='<lineups country="USA">
 <headend headendId="TX02217">
  <name>Grande Gables at The Terrace</name>
  <mso msoId="17541">Grande Communications</mso>
  <marketIds>
   <marketId type="DMA">635</marketId>
  </marketIds>
  <postalCodes>
   <postalCode>11111</postalCode>
   <postalCode>22222</postalCode>
   <postalCode>33333</postalCode>
   <postalCode>78746</postalCode>
  </postalCodes>
  <location>Austin</location>
  <lineup>
   <station prgSvcId="20014">
    <chan effDate="2006-01-16" tier="1">002</chan>
   </station>
   <station prgSvcId="10722">
    <chan effDate="2006-01-16" tier="1">003</chan>
   </station>
  </lineup>
  <areasServed>
   <area>
    <community>Thorndale</community>
    <county code="45331" size="D">Milam</county>
    <state>TX</state>
   </area>
   <area>
    <community>Thrall</community>
    <county code="45491" size="B">Williamson</county>
    <state>TX</state>
   </area>
  </areasServed>
 </headend></lineups>';

$dom = new DOMDocument();
$dom->loadXML($string);

$xpath = new DOMXPath($dom);
$elements= $xpath->query('//lineups/headend/postalCodes/*[text()=78746]');

if (!is_null($elements)) {
  foreach ($elements as $element) {
    echo "<br/>[". $element->nodeName. "]";

    $nodes = $element->childNodes;
    foreach ($nodes as $node) {
      echo $node->nodeValue. "\n";
    }
  }
}

出力:

<br/>[postalCode]78746
于 2013-03-11T18:24:47.070 に答える