Search code examples
phpnodesxmlreader

Reading child nodes with XMLReader in PHP


Background: I have a list of star systems collected from resource material and from m.sarna.net. That data gets converted to an xml file using a different PHP file, not discussed here. I'm calling the php file below from a browser, passing variables for name and length. I'm trying to use the XMLReader to target specific nodes for retrieval, but getting back way too much data. Instead of returning one element, then moving on to the next, I'm getting the same element repeatedly, thousands if I let it. It should be simple, but I don't know what I'm missing. Please help. This is for Battletech, if you're interested. While there are 7889 jump paths for this file, the file containing double-jumps, up to 60 light year distance, contains about 24000 entries, so makes for a file around 4MB in size. Not something I want to read into memory each time I need it.

<jumpPathsStandard summary="Unique Jump Paths under 30 light years: 7889">
        <Terra>
                <from>Terra</from>
                <to>Thorin</to>
                <distance>24.35</distance>
                <fromX>0.00</fromX>
                <fromY>0.00</fromY>
                <toX>-23.73</toX>
                <toY>8.08</toY>
        </Terra>
        <Terra>
                <from>Terra</from>
                <to>Yorii</to>
                <distance>22.47</distance>
                <fromX>0.00</fromX>
                <fromY>0.00</fromY>
                <toX>-8.08</toX>
                <toY>21.39</toY>
        </Terra>
        <Terra_Firma>
                <from>Terra Firma</from>
                <to>Woodstock</to>
                <distance>22.36</distance>
                <fromX>22.69</fromX>
                <fromY>-33.90</fromY>
                <toX>44.60</toX>
                <toY>-37.03</toY>
        </Terra_Firma>
        <Tetersen>
                <from>Tetersen</from>
                <to>Tharkad</to>
                <distance>12.53</distance>
                <fromX>-204.99</fromX>
                <fromY>146.05</fromY>
                <toX>-215.94</toX>
                <toY>152.83</toY>
        </Tetersen>


$i=0;
if(isset($_GET["name"]) && isset($_GET["length"])) {
        switch ($_GET["length"]) {
                case "short":
                        $xml = new XMLReader();
                        $xml->open($shortfile);
                        $items = array();
                        while($xml->read() && $xml->name !== $_GET['name']);
                        while($xml->name === $_GET['name']) {
                                $item = array();
                                $node = new SimpleXMLElement($xml->readOuterXML());
                                if($node->from == $_GET['name']) {
                                        echo $i.":      ".$node->from." | ".$node->to." | ".$node->distance." | ".$node->fromX." | ".$node->fromY." | ".$node->toX." | ".$node->toY."<br>";
                                        $i++;
                                }
                        }
                        $xml->$close();
                break;
                case "long":
                        # Future use;
                break;
        }
}

What I'm getting for output: Testing

0: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08

1: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08

2: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08

3: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08

4: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08

5: Terra | Thorin | 24.35 | 0.00 | 0.00 | -23.73 | 8.08 ...


Solution

  • You are missing the code which moves onto the next item in the read loop

    $xml->next($_GET['name']);
    

    So...

    while($xml->name === $_GET['name']) {
        $item = array();
        $node = new SimpleXMLElement($xml->readOuterXML());
        if($node->from == $_GET['name']) {
            echo $i.":      ".$node->from." | ".$node->to." | ".$node->distance." | ".$node->fromX." | ".$node->fromY." | ".$node->toX." | ".$node->toY."<br>";
            $i++;
        }
    
        // Next item...
        $xml->next($_GET['name']);
    }
    $xml->$close();