0
\$\begingroup\$

I have stored in a XML file some Travel packages, each package has a code( the codes are stored in an array = $code).

I am using the below code to pull the requested data from the XML based on the given code. At this time I have copy/paste the code for each given code, but I have lots more and I dont want to copy paste code over and over

How can I simplify the below code so I don't have to paste it for all code that I have?

 <?php $code = array("BAS12", "BAS12", "BAS13", "BAS14"); $dom = new DOMDocument(); $xpath = new DOMXPath($dom); $reader = new XMLReader(); $reader->open("file.xml"); while ($reader->read()) { if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'Hotel') { $node = $dom->importNode($reader->expand(), true); $dom->appendChild($node); $nume1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/HotelName)', $node); $tara1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Country)', $node); $oras1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/City)', $node); $adresa1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Adress)', $node); $stele1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Stars)', $node); $masa1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/TipMasa)', $node); $camera1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/TipCamera)', $node); $pret1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Pret)', $node); $descriere1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Descriere)', $node); $persoane1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Persoane)', $node); $img1 = $xpath->evaluate('string(self::Hotel[HotelCode = "'.$code[0].'"]/Imagine1)', $node); $dom->removeChild($node); if ($nume1) { break; } if ($tara1) { break; } if ($oras1) { break; } if ($adresa1) { break; } if ($stele1) { break; } if ($camera1) { break; } if ($masa1) { break; } if ($pret1) { break; } if ($persoane1) { break; } if ($img1) { break; } } } ?> 
\$\endgroup\$

    1 Answer 1

    1
    \$\begingroup\$

    Why don't you read the code into a variable and check if it is in the array of codes? After that fill up an array with the results.

    Nearly every time you have a variable with a counter in the name, you should use arrays.

    Another optimization is using XMLReader::next() to go directly to the next sibling without reading the child nodes.

    You don't need to append the imported node, you need to provide it as a context in the DOMXpath::evaluate() calls anyway.

    $codes = ["BAS11", "BAS12", "BAS13", "BAS14"]; $hotels = []; $dom = new DOMDocument(); $xpath = new DOMXPath($dom); $reader = new XMLReader(); $reader->open($filename); // look for the first Hotel element (include descendants) while ($reader->read() && $reader->localName !== 'Hotel') { continue; } // while you have an Hotel element while ($reader->localName === 'Hotel') { // no need to append the node to the document, just import it $node = $dom->importNode($reader->expand(), true); // read the HotelCode $code = $xpath->evaluate('normalize-space(./HotelCode)', $node); // if it is in the list if (in_array($code, $codes)) { // read the values $hotels[$code] = [ 'name' => $xpath->evaluate('string(./HotelName)', $node), 'country' => $xpath->evaluate('string(./Country)', $node), //... ]; } // move directly to the next Hotel sibling $reader->next('Hotel'); } var_dump($hotels); 
    \$\endgroup\$