0

非常に大きな (700MB) XML ファイルを読み取るために、XMLReader/SimpleXML ハイブリッド関数を作成しようとしています。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 を使用するだけですが、これまでのグーグルでは英語のノード (1 つは名前、もう 1 つは説明) が繰り返し出現するため、SimpleXML が前進する方法のように見えましたが、まだ喜びはありません。

助言がありますか?良いガイドはありますか?php.net の XMLReader ドキュメントは、他の多くの PHP 機能に比べてひどく不足しており、一般的に、明確で簡潔な詳細なガイドを見つけるのは難しいようです。

4

2 に答える 2

4

それでもその配列を作成できる場合、XML ファイルはおそらくそれほど大きくありません:)。たとえば、ファイル全体を simplexml でロードしてみてください。それほど多くのメモリを消費しないことに驚くかもしれません。

とにかく、まだ XMLReader を使用したい場合は、要素、子にアクセスし、フラグメントをsに変換するなどの操作を実行できるXMLReader Iterator ライブラリをよくお勧めします。XMLReaderSimpleXMLElement

以下は、上記の例とほぼ同じ例です。

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 要素に設定されます。私の例 (これら 2 つの部分) で行ったように、それらを文字列にキャストして、SimpleXMLElements の代わりに文字列を配置することをお勧めします。これがおそらく問題でした。そうでない場合は、libxml のバージョンを確認します。$items(string)

var_dump(LIBXML_DOTTED_VERSION); # string(5) "2.7.8"

そしてそれを報告してください(つまり、ライブラリXMLReaderが基づいています)。また、SimpleXMLElement ( var_dump($sxml->asXML());) をデバッグして、予想される XML がロードされたことを確認します。

ところで私が提案するライブラリ。すぐに試してみたい場合は、単一のインクルード ファイルも付属しています。

前回、ライブラリが次の場所にあることを提案しました。


編集:next()同じ名前の兄弟を常に反復処理するときに役立つ、使用方法を示すライブラリのない追加のハイブリッド バージョン: <Item>:

$xmlFile = "xmlreader-17262798.xml";

$reader = new XMLReader();
$reader->open($xmlFile);

$reader->read() && $reader->read(); // init and position onto first element

$items = array();
while ($reader->next('Item')) {
    $node = new SimpleXMLElement($reader->readOuterXML());

    $items[] = array(
        'itemkey'     => $node->ItemKey,
        'englishName' => $node->Name->English,
        'englishDesc' => $node->Description->English,
    );
}
于 2013-06-23T17:37:13.020 に答える
-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;
}
于 2013-06-23T17:40:12.737 に答える