programing

PHP에서 XMLReader를 사용하는 방법?

nasanasas 2020. 10. 20. 07:41
반응형

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에 대한 좋은 자습서를 찾지 못했고 각 요소 콘텐츠를 데이터베이스에 저장할 수있는 방법을보고 싶습니다.


그것은 모두 작업 단위의 크기에 달려 있지만 각 <product/>노드를 연속적 으로 처리하려고 시도하고 있다고 생각합니다 .

이를 위해 가장 간단한 방법은 XMLReader를 사용하여 각 노드로 이동 한 다음 SimpleXML을 사용하여 액세스하는 것입니다. 이렇게하면 한 번에 하나의 노드를 처리하고 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 만

  • 장점 : 빠르고 적은 메모리 사용

  • 단점 : 작성 및 디버그가 지나치게 어렵고 유용한 작업을 수행하려면 많은 사용자 영역 코드가 필요합니다. Userland 코드는 느리고 오류가 발생하기 쉽습니다. 또한 유지 관리 할 코드 줄이 더 많이 남습니다.

XMLReader + SimpleXML

  • 장점 : 많은 메모리를 사용하지 않고 (단 하나의 노드를 처리하는 데 필요한 메모리 만) SimpleXML은 이름에서 알 수 있듯이 사용하기가 정말 쉽습니다.

  • 단점 : 각 노드에 대해 SimpleXMLElement 개체를 만드는 것은 그리 빠르지 않습니다. 그것이 당신에게 문제인지 이해하기 위해 정말로 벤치마킹해야합니다. 하지만 아무리 평범한 기계라도 초당 1000 개의 노드를 처리 할 수 ​​있습니다.

XMLReader + DOM

  • 장점 : SimpleXML만큼 많은 메모리를 사용하며 XMLReader :: expand () 는 새 SimpleXMLElement를 만드는 것보다 빠릅니다. 사용이 가능했으면 좋겠 simplexml_import_dom()는데 그 경우에는 안되는 것 같습니다

  • 단점 : DOM은 작업하기가 귀찮습니다. XMLReader와 SimpleXML의 중간입니다. XMLReader만큼 복잡하고 어색하지는 않지만 SimpleXML로 작업하는 데 수년이 걸립니다.

나의 조언 : SimpleXML로 프로토 타입을 작성하고 그것이 당신에게 맞는지 확인하라. 성능이 가장 중요하다면 DOM을 사용해보십시오. 가능한 한 XMLReader에서 멀리 떨어져 있습니다. 더 많은 코드를 작성할수록 버그가 발생하거나 성능 회귀가 발생할 가능성이 높아집니다.


속성으로 형식화 된 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();

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();
}

받아 들여진 대답은 나에게 좋은 출발을했지만 내가 원했던 것보다 더 많은 수업과 더 많은 처리를 가져왔다. 그래서 이것은 내 해석입니다.

$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();

XMLReader is well documented on PHP site. This is a XML Pull Parser, which means it's used to iterate through nodes (or DOM Nodes) of given XML document. For example, you could go through the entire document you gave like this:

<?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();
?>

It is then up to you to decide how to deal with the node returned by XMLReader::expand().


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));
    }
}

참고URL : https://stackoverflow.com/questions/1835177/how-to-use-xmlreader-in-php

반응형