0

I'm having an issue with the moveToAttribute method from PHP's XMLReader class.
I don't want to read in each line of the XML file. I want to have the capability to traverse the XML file, without going in sequential order; that is, random access. I thought using moveToAttribute would move the cursor to a node with the attribute value specified, where I can then conduct processing on its inner nodes, but this is not working out as planned.

Here's a snippet of the xml file:

<?xml version="1.0" encoding="Shift-JIS"?>
    <CDs>
        <Cat Type="Rock">
            <CD>
                <Name>Elvis Prestley</Name>
                <Album>Elvis At Sun</Album>
            </CD>
            <CD>
                <Name>Elvis Prestley</Name>
                <Album>Best Of...</Album>
            </CD>
        </Cat>
        <Cat Type="JazzBlues">
            <CD>
                <Name>B.B. King</Name>
                <Album>Singin' The Blues</Album>
            </CD>
            <CD>
                <Name>B.B. King</Name>
                <Album>The Blues</Album>
            </CD>
        </Cat>
    </CDs>

Here is my PHP code:

<?php

    $xml = new XMLReader();
    $xml->open("MusicCatalog.xml") or die ("can't open file");
    $xml->moveToAttribute("JazzBlues");

    print $xml->nodeType . PHP_EOL; // 0
    print $xml->readString() . PHP_EOL; // blank ("")
?>

What am I doing wrong, with regards to moveToAttribute? How can I randomly access nodes using a node's attribute? I want to target node Cat Type="JazzBlues" without doing it sequentially (i.e. $xml->read()), and then process its inner nodes.

Thank you very much.

Don
  • 863
  • 1
  • 8
  • 22
user717236
  • 4,959
  • 19
  • 66
  • 102
  • 1
    You might be better served using an XML parser like SimpleXML with xpath support http://php.net/manual/en/simplexmlelement.xpath.php – Mike Brant Aug 02 '12 at 15:39
  • Yeah, I think that's a good idea. I thought I didn't need it, but it seems that XMLReader is one or more combinations of buggy and not documented well (enough). – user717236 Aug 02 '12 at 15:54
  • 1
    I have used SimpleXML a lot and it is generally pretty good to work with IMO. – Mike Brant Aug 02 '12 at 16:05

1 Answers1

1

i think there is no way to avoid XMLReader::read. XMLreader::moveToAttribute only works if the XMLReader already points to an element. Additionally you also can check XMLReader::moveToAttribute's return value to detect possible failures. Maybe try something like this:

<?php
$xml = new XMLReader();
$xml->open("MusicCatalog.xml") or die ("can't open file");
while ($xml->read() && xml->name != "Cat"){ }
//the parser now found the "Cat"-element
//(or the end of the file, maybe you should check that)
//and points to the desired element, so moveToAttribute will work
if (!$xml->moveToAttribute("Type")){
    die("could not find the desired attribute");
}
//now $xml points to the attribute, so you can access the value just by $xml->value
echo "found a 'cat'-element, its type is " . $xml->value;
?>

this piece of code should print the value of the type-attribute of the first cat-element in the file. i dont know what you want to do with the file, so you have to change the code for your idea. for processing the inner nodes you can use:

<?php
//continuation of the code above
$depth = $xml->depth;
while ($xml->read() && $xml->depth >= $depth){
    //do something with the inner nodes
}
//the first time this Loop should fail is when the parser encountered
//the </cat>-element, because the depth inside the cat-element is higher than
//the depth of the cat-element itself
//maybe you can search for other cat-nodes here, after you processed one

i cant tell you, how to rewrite this code for a random-access example, but i hope, i could help you with this.

Sirac
  • 693
  • 4
  • 18