Jodi Warren
Jodi Warren

Reputation: 410

In PHP, how can I get an XML attribute based on a variable?

I'm retrieving files like so (from the Internet Archive):

<files>
  <file name="Checkmate-theHumanTouch.gif" source="derivative">
    <format>Animated GIF</format>
    <original>Checkmate-theHumanTouch.mp4</original>
    <md5>72ec7fcf240969921e58eabfb3b9d9df</md5>
    <mtime>1274063536</mtime>
    <size>377534</size>
    <crc32>b2df3fc1</crc32>
    <sha1>211a61068db844c44e79a9f71aa9f9d13ff68f1f</sha1>
  </file>
  <file name="CheckmateTheHumanTouch1961.thumbs/Checkmate-theHumanTouch_000001.jpg" source="derivative">
    <format>Thumbnail</format>
    <original>Checkmate-theHumanTouch.mp4</original>
    <md5>6f6b3f8a779ff09f24ee4cd15d4bacd6</md5>
    <mtime>1274063133</mtime>
    <size>1169</size>
    <crc32>657dc153</crc32>
    <sha1>2242516f2dd9fe15c24b86d67f734e5236b05901</sha1>
  </file>
</files>

They can have any number of <file>s, and I'm solely looking for the ones that are thumbnails. When I find them, I want to increase a counter. When I've gone through the whole file, I want to find the middle Thumbnail and return the name attribute.

Here's what I've got so far:

//pop previously retrieved XML file into a variable
$elem = new SimpleXMLElement($xml_file);
//establish variable
$i = 0;

// Look through each parent element in the file
foreach ($elem as $file) {
    if ($file->format == "Thumbnail"){$i++;}
}
    //find the middle thumbnail.
$chosenThumb = ceil(($i/2)-1);
    //Gloriously announce the name of the chosen thumbnail.
echo($elem->file[$chosenThumb]['name']);`

The final echo doesn't work because it doesn't like have a variable choosing the XML element. It works fine when I hardcode it in. Can you guess that I'm new to handling XML files?

Edit: Francis Avila's answer from below sorted me right out!:

$sxe = simplexml_load_file($url);
$thumbs = $sxe->xpath('/files/file[format="Thumbnail"]');
$n_thumbs = count($thumbs);
$middlethumb = $thumbs[(int) ($n_thumbs/2)];
$happy_string = (string)$middlethumb[name];
echo $happy_string;

Upvotes: 1

Views: 231

Answers (3)

Francis Avila
Francis Avila

Reputation: 31621

Use XPath.

$sxe = simplexml_load_file($url);
$thumbs = $sxe->xpath('/files/file[format="Thumbnail"]');
$n_thumbs = count($thumbs);
$middlethumb = $thumbs[(int) ($n_thumbs/2)];
$middlethumbname = (string) $middlethumb['name'];

You can also accomplish this with a single XPath expression if you don't need the total count:

$thumbs = $sxe->xpath('/files/file[format="Thumbnail"][position() = floor(count(*) div 2)]/@name');
$middlethumbname = (count($thumbs)) ? $thumbs[0]['name'] : '';

A limitation of SimpleXML's xpath method is that it can only return nodes and not simple types. This is why you need to use $thumbs[0]['name']. If you use DOMXPath::evaluate(), you can do this instead:

$doc = new DOMDocument();
$doc->loadXMLFile($url);
$xp = new DOMXPath($doc);
$middlethumbname = $xp->evaluate('string(/files/file[format="Thumbnail"][position() = floor(count(*) div 2)]/@name)');

Upvotes: 5

Silviu-Marian
Silviu-Marian

Reputation: 10907

Some problems:

  • Middle thumbnail is incorrectly calculated. You'll have to keep a separate array for those thumbs and get the middle one using count.
  • file might need to be {'file'}, I'm not sure how PHP sees this.
  • you don't have a default thumbnail
  • Code you should use is this one:

    $files = new SimpleXMLElement($xml_file);
    $thumbs = array();
    
    foreach($files as $file)
        if($file->format == "Thumbnail")
            $thumbs[] = $file;
    
    $chosenThumb = ceil((count($thumbs)/2)-1);
    echo (count($thumbs)===0) ? 'default-thumbnail.png' : $thumbs[$chosenThumb]['name'];
    

/edit: but I recommend that guy's solution, to use XPath. Way easier.

Upvotes: 0

Milindu Sanoj Kumarage
Milindu Sanoj Kumarage

Reputation: 2774

$elem->file[$chosenThumb] will give the $chosenThumb'th element from the main file[] not the filtered(for Thumbnail) file[], right?

foreach ($elem as $file) {
    if ($file->format == "Thumbnail"){
    $i++;
    //add this item to a new array($filteredFiles)
    }
}

$chosenThumb = ceil(($i/2)-1);

//echo($elem->file[$chosenThumb]['name']);
  echo($filteredFiles[$chosenThumb]['name']);

Upvotes: 0

Related Questions