2017-07-19 3 views
0

ich viele Tutorials hier in Überlauf sah, aber ich konnte nicht verstehen, was ich vermisst .. Also ich brauche Hilfe ..XML get Attribute

Ich habe eine XML, die es online ist, und ich versuche zu parsen es wie folgt aus:

<products> 
    <product> 
    <id>13389</id> 
    <name><![CDATA[ product name ]]></name> 
    <category id="14"><![CDATA[ Shoes > test1 ]]></category> 
    <price>41.30</price> 
</products> 

Soweit ich die XML lese und es so Parsen:

$reader = new XMLReader(); 
$reader->open($product_xml_link); 
while($reader->read()) { 
if($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'product') { 
    $product = new SimpleXMLElement($reader->readOuterXml()); 
    $pid = $product->id; 
    $name = $product->name; 
    $name = strtolower($name); 
    $link = $product->link; 
    $price = $product->Price; 
    ... 
    ... 
} 
} //end while loop 

wie Sie sehen können, gibt es eine ID in der Kategorie Tag ist .. Dies ist das ist eine, die ich gerne zu meinem Code greifen und vertreiben würde.

Ich habe so etwas wie dies:

echo "prodcut= " . (string)$product->category->getAttribute('id'); 

Der Fehler, den ich bekommen habe ist: Call to undefined Methode SimpleXMLElement :: getAttribute()

Ich brauche diese ID, um es zu testen, bevor Einsatz es in DB .. So,

if($id = 600) { 
//insert DB 
} 

Antwort

1

Hier sind einige Dinge. Zuerst $product = new SimpleXMLElement($reader->readOuterXml()); bedeutet, dass Sie das alles als separates XML-Dokument lesen und erneut analysieren. Hier ist expand(), das direkt einen DOM-Knoten zurückgibt und DOM-Knoten können in SimpleXML importiert werden.

Für Attribute verwenden Array-Syntax ..

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

// an document to expand to 
$document = new DOMDocument(); 

// find the first product node 
while ($reader->read() && $reader->localName !== 'product') { 
    continue; 
} 

while ($reader->localName === 'product') { 
    $product = simplexml_import_dom($reader->expand($document)); 
    $data = [ 
    'id' => (string)$product->id, 
    'name' => (string)$product->name, 
    'category_id' => (string)$product->category['id'], 
    // ... 
    ]; 
    var_dump($data); 
    // move to the next product sibling 
    $reader->next('product'); 
} 
$reader->close(); 

Ausgang:

array(3) { 
    ["id"]=> 
    string(5) "13389" 
    ["name"]=> 
    string(14) " product name " 
    ["category_id"]=> 
    string(2) "14" 
} 

Natürlich können Sie den DOM direkt verwenden können, und die Detaildaten unter Verwendung von XPath-Ausdrücken holen:

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

// prepare a document to expand to 
$document = new DOMDocument(); 
// and an xpath instance to use 
$xpath = new DOMXpath($document); 

// find the first product node 
while ($reader->read() && $reader->localName !== 'product') { 
    continue; 
} 

while ($reader->localName === 'product') { 
    $product = $reader->expand($document); 
    $data = [ 
    'id' => $xpath->evaluate('string(id)', $product), 
    'name' => $xpath->evaluate('string(name)', $product), 
    'category_id' => $xpath->evaluate('string(category/@id)', $product), 
    // ... 
    ]; 
    var_dump($data); 
    // move to the next product sibling 
    $reader->next('product'); 
} 
$reader->close(); 
+0

Hallo, dank für Ihre Antwort .. Darf ich fragen, ob es einen einfacheren Weg, ohne Arrays ? Mein Code wie ist, ist das möglich, die ID zu greifen? ohne $ document = new DOMDocument(); // und eine zu verwendende Xpath-Instanz $ xpath = neuer DOMXpath ($ document); oder irgendwas? –

+0

Das Array ist nur eine Möglichkeit, die gelesenen Daten zu sammeln.Verwenden Sie Variablen, Call Functions, ... und gut, Sie können meine FluentDOM-Bibliothek verwenden. Es erweitert XMLReader/DOM und abstrahiert etwas davon: https://github.com/FluentDOM/FluentDOM/blob/master/examples/XMLReader/sitemap.php :-) – ThW

+0

Ich behalte meine Lösung so, wie sie ist, mit einigen Änderungen erzählt über: $ document = ... $ xpath =. . . Ich habe die Code-Zeile gelöscht: $ product = new SimpleXMLElement und drehte alle meine Daten zu Array, wie Sie erwähnen .. Jetzt sehe ich, dass das Parsen XML ein wenig langsamer ist ... Das XML hat 5.500 Produkte (die nicht sehr viel sind). Bevor irgendwelche Änderungen, die XML ist ein bisschen schneller glaube ich .. Irgendwelche Vorschläge? –

0

möchten Sie alle Produkte in Schleife, und extrahieren Sie die untergeordneten Elemente id, name, link und price Textinhalt? das kann wie geschehen:

foreach((@DOMDocument::loadHTML($xml))->getElementsByTagName("product") as $product){ 
    $vars=array('id','name','link','price'); 
    foreach($vars as $v){ 
     ${$v}=$product->getElementsByTagName($v)->item(0)->textContent; 
    } 
    unset($v,$vars); 
    //now you have $id , $name , $link , $price as raw text, and $product is the DOMNode for the <product> tag. 
} 

und wenn Sie 600 id möchten, fügen Sie if($id!=600){continue;} nach dem ungesetzt verarbeiten(); - und wenn Sie etwas CPU sparen wollen, sollten Sie auch eine Pause einfügen; am Ende der foreach-Schleife in diesem Fall. (Dann wird er Looping stoppen, sobald es id 600 gefunden)

Edit: fixiert, um einen Code zu knacken Tippfehler, wird der Code nicht ohne Tippfehler arbeiten beheben

edit: wenn Sie XPath verwenden, um die richtige zu finden Element, würde es $product=(new DOMXpath((@DOMDOcument::loadHTML($xml))))->query('//product/id[text()=\'600\']')->item(0)->parentNode;

bearbeiten sein: fixed einen anderen Code-breaking Tippfehler (items(0) ->item(0))