86

私は次の 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 に関するこれに関する適切なチュートリアルは見つかりませんでした。各要素のコンテンツをデータベースに格納する方法を知りたいと思っています。

4

7 に答える 7

230

<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 からできるだけ離れてください。記述するコードが多いほど、バグが発生したり、パフォーマンスが低下したりする可能性が高くなることに注意してください。

于 2009-12-02T19:45:04.347 に答える
12

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

データ.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();
于 2012-10-05T17:06:24.043 に答える
7

私の 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();
}
于 2014-10-15T18:02:44.370 に答える
2

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()によって返されるノードをどのように処理するかを決定するのはあなた次第です。

于 2009-12-02T19:42:11.200 に答える
2
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));
    }
}
于 2013-10-10T07:04:36.863 に答える