web-dev-qa-db-ja.com

PHPでXMLReaderを使用する方法は?

私は次のXMLファイルを持っていますが、ファイルはかなり大きく、simplexmlを開いてファイルを読み取ることができなかったので、PHPで成功せずにXMLReaderを試しています

<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
    <last_updated>2009-11-30 13:52:40</last_updated>
    <product>
        <element_1>foo</element_1>
        <element_2>foo</element_2>
        <element_3>foo</element_3>
        <element_4>foo</element_4>
    </product>
    <product>
        <element_1>bar</element_1>
        <element_2>bar</element_2>
        <element_3>bar</element_3>
        <element_4>bar</element_4>
    </product>
</products>

残念ながら、これについてはPHP=の良いチュートリアルは見つかりませんでした。各要素のコンテンツをデータベースに保存する方法を知りたいと思います。

74
Shadi Almosri

すべては作業単位の大きさに依存しますが、各_<product/>_ノードを連続して処理しようとしていると思います。

そのための最も簡単な方法は、XMLReaderを使用して各ノードにアクセスし、次にSimpleXMLを使用してそれらのノードにアクセスすることです。この方法では、一度に1つのノードを扱い、SimpleXMLの使いやすさを活用するため、メモリ使用量を低く抑えます。例えば:

_$z = new XMLReader;
$z->open('data.xml');

$doc = new DOMDocument;

// move to the first <product /> node
while ($z->read() && $z->name !== 'product');

// now that we're at the right depth, hop to the next <product/> until the end of the tree
while ($z->name === 'product')
{
    // either one should work
    //$node = new SimpleXMLElement($z->readOuterXML());
    $node = simplexml_import_dom($doc->importNode($z->expand(), true));

    // now you can use $node without going insane about parsing
    var_dump($node->element_1);

    // go to next <product />
    $z->next('product');
}
_

さまざまなアプローチの長所と短所の概要:

XMLReaderのみ

  • 長所:高速、メモリ使用量が少ない

  • 短所:作成とデバッグが非常に難しく、便利なことを行うには多くのユーザーランドコードが必要です。ユーザーランドコードは遅く、エラーを起こしやすいです。さらに、維持するコードの行が増えます

XMLReader + SimpleXML

  • 長所:メモリをあまり使用せず(1つのノードを処理するために必要なメモリのみ)、SimpleXMLは、その名が示すように、本当に使いやすいです。

  • 短所:各ノードのSimpleXMLElementオブジェクトの作成は非常に高速ではありません。それがあなたにとって問題であるかどうかを理解するためには、本当にそれをベンチマークする必要があります。ただし、控えめなマシンでも、1秒あたり1,000ノードを処理できます。

XMLReader + DOM

  • 長所:SimpleXMLとほぼ同じ量のメモリを使用し、 XMLReader :: expand() は新しいSimpleXMLElementを作成するよりも高速です。 simplexml_import_dom()を使用できればよかったのですが、その場合はうまくいかないようです

  • 短所:DOMを使用するのは面倒です。 XMLReaderとSimpleXMLの中間です。 XMLReaderほど複雑で厄介ではありませんが、SimpleXMLでの作業から数年離れています。

私のアドバイス:SimpleXMLでプロトタイプを書き、それがあなたのために動くかどうか確かめてください。パフォーマンスが最も重要な場合は、DOMを試してください。 XMLReaderから可能な限り離れてください。記述するコードが多いほど、バグの導入やパフォーマンスの低下が発生する可能性が高くなることを忘れないでください。

211
Josh Davis

属性でフォーマットされたxmlの場合...

data.xml:

<building_data>
<building address="some address" lat="28.902914" lng="-71.007235" />
<building address="some address" lat="48.892342" lng="-75.0423423" />
<building address="some address" lat="58.929753" lng="-79.1236987" />
</building_data>

pHPコード:

$reader = new XMLReader();

if (!$reader->open("data.xml")) {
    die("Failed to open 'data.xml'");
}

while($reader->read()) {
  if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'building') {
    $address = $reader->getAttribute('address');
    $latitude = $reader->getAttribute('lat');
    $longitude = $reader->getAttribute('lng');
}

$reader->close();
9
try5tan3

私のXML解析ライフのほとんどは、大量のXML(Amazon MWS)から有用な情報のナゲットを抽出することに費やされています。そのため、私の答えは、特定の情報のみが必要であり、それがどこにあるかを知っていることを前提としています。

XMLReaderを使用する最も簡単な方法は、どのタグから情報を取り出して使用するかを知ることです。 XMLの構造を知っていて、多くの一意のタグがある場合、最初のケースを使用するのは簡単だと思います。ケース2と3は、より複雑なタグに対してどのように実行できるかを示すためのものです。これは非常に高速です。 PHPで最速のXMLパーサーとは何ですか?

このようなタグベースの解析を行う際に覚えておくべき最も重要なことは、if ($myXML->nodeType == XMLReader::ELEMENT) {...を使用することです。これは、空白やノードを閉じるのではなく、開いているノードのみを処理していることを確認します。

function parseMyXML ($xml) { //pass in an XML string
    $myXML = new XMLReader();
    $myXML->xml($xml);

    while ($myXML->read()) { //start reading.
        if ($myXML->nodeType == XMLReader::ELEMENT) { //only opening tags.
            $tag = $myXML->name; //make $tag contain the name of the tag
            switch ($tag) {
                case 'Tag1': //this tag contains no child elements, only the content we need. And it's unique.
                    $variable = $myXML->readInnerXML(); //now variable contains the contents of tag1
                    break;

                case 'Tag2': //this tag contains child elements, of which we only want one.
                    while($myXML->read()) { //so we tell it to keep reading
                        if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') { // and when it finds the amount tag...
                            $variable2 = $myXML->readInnerXML(); //...put it in $variable2. 
                            break;
                        }
                    }
                    break;

                case 'Tag3': //tag3 also has children, which are not unique, but we need two of the children this time.
                    while($myXML->read()) {
                        if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') {
                            $variable3 = $myXML->readInnerXML();
                            break;
                        } else if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Currency') {
                            $variable4 = $myXML->readInnerXML();
                            break;
                        }
                    }
                    break;

            }
        }
    }
$myXML->close();
}
6
Josiah

受け入れられた答えは良いスタートでしたが、私が望んでいたよりも多くのクラスと処理をもたらしました。これが私の解釈です:

$xml_reader = new XMLReader;
$xml_reader->open($feed_url);

// move the pointer to the first product
while ($xml_reader->read() && $xml_reader->name != 'product');

// loop through the products
while ($xml_reader->name == 'product')
{
    // load the current xml element into simplexml and we’re off and running!
    $xml = simplexml_load_string($xml_reader->readOuterXML());

    // now you can use your simpleXML object ($xml).
    echo $xml->element_1;

    // move the pointer to the next product
    $xml_reader->next('product');
}

// don’t forget to close the file
$xml_reader->close();
4
Francis Lewis

XMLReaderは PHPサイト で文書化されています。これはXMLプルパーサーです。つまり、特定のXMLドキュメントのノード(またはDOMノード)を反復処理するために使用されます。たとえば、次のように指定したドキュメント全体を閲覧できます。

<?php
$reader = new XMLReader();
if (!$reader->open("data.xml"))
{
    die("Failed to open 'data.xml'");
}
while($reader->read())
{
    $node = $reader->expand();
    // process $node...
}
$reader->close();
?>

XMLReader :: expand() によって返されるノードの処理方法を決定するのは、ユーザー次第です。

2
Percutio
Simple example:

public function productsAction()
{
    $saveFileName = 'ceneo.xml';
    $filename = $this->path . $saveFileName;
    if(file_exists($filename)) {

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

    $countElements = 0;

    while($reader->read()) {
        if($reader->nodeType == XMLReader::ELEMENT) {
            $nodeName = $reader->name;
        }

        if($reader->nodeType == XMLReader::TEXT && !empty($nodeName)) {
            switch ($nodeName) {
                case 'id':
                    var_dump($reader->value);
                    break;
            }
        }

        if($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == 'offer') {
            $countElements++;
        }
    }
    $reader->close();
    exit(print('<pre>') . var_dump($countElements));
    }
}
2
sebob