0

I have created a simplexml php file that will load all the xml items I would like to pull. The only issue is there are child items that lie under a item with an attribute. When I try to pull the child items, nothing shows. I am still relatively new to using simplexml

XML

<Mediainfo version="0.7.62">
    <File>
        <track type="General">
            <UniqueID_String>242652904449958064145306342749155800074 (0xB68D3FDDBE0F9B3E865F70325496B40A)</UniqueID_String>
            <CompleteName>D:\Encoder\videos\raw\063 - 077 (Season_02)\064 - A Pirate-Loving Town Arrival at Whiskey Peak.mkv</CompleteName>
            <Format>Matroska</Format>
            <Format_Version>Version 1</Format_Version>
            <FileSize_String>40.0 MiB</FileSize_String>
            <Duration_String>24mn 6s</Duration_String>
            <OverallBitRate_String>232 Kbps</OverallBitRate_String>
            <Encoded_Date>UTC 2008-08-26 15:24:58</Encoded_Date>
            <Encoded_Application>mkvmerge v2.2.0 (&apos;Turn It On Again&apos;) built on Mar  4 2008 12:58:26</Encoded_Application>
            <Encoded_Library_String>libebml v0.7.7 + libmatroska v0.8.1</Encoded_Library_String>
        </track>
    </File>
</Mediainfo>

I am trying to grab

<UniqueID_String>242652904449958064145306342749155800074 (0xB68D3FDDBE0F9B3E865F70325496B40A)</UniqueID_String>

under

<track type="General">

PHP

$lib  = simplexml_load_file("media.xml");
$xml = $lib->File;
$gen = $xml->track['General'];
$vid = $xml->track['Video'];
$aud = $xml->track['Audio'];


//General
$format = $gen->Format;
$app = $gen->Encoded_Application;
$size = $gen->FileSize_String;
$dur = $gen->Duration_String;

echo $format;

//Video
$vformat = $vid->Format;
$vbit = $vid->BitRate_Nominal_String;
$width = $vid->Width_String;
$height = $vid->Height_String;
$aspect = $vid->DisplayAspectRatio_String;
$frame = $vid->FrameRate_String;
$encode = $vid->Encoded_Library_String;
$encodes = $vid->Encoded_Library_Settings;

//Audio
$aformat = $aud->Format;
$compress = $aud->Compression_Mode_String;
$lang = $aud->Language_String;
Diego Pino
  • 11,278
  • 1
  • 55
  • 57
Ryahn
  • 537
  • 7
  • 24

3 Answers3

1

There is a difference between accessing an Attribute and a Child Element in SimpleXML.

So if you want to access:

  • a child element use object property access
  • an attribute use array access

This is outlined as well in the SimpleXML Basic Examples.

In your case you want to access a child of a child:

$xml = simplexml_load_file("data-15308758.xml");

### first track in first file ###
echo $xml->File->track->UniqueID_String, "\n"; 

### each track with attribute type="General" in each file ###
$count = 0;
foreach($xml->xpath('/*/File/track[@type="General"]') as $track)
{
    echo ++$count, ': ', $track->UniqueID_String, "\n";
}

See http://eval.in/12273

hakre
  • 193,403
  • 52
  • 435
  • 836
  • I am trying to grab a child that is under an element with an attribute. If I remove the attribute and I can grab it. – Ryahn Mar 09 '13 at 08:42
  • I updated the answer. It was not clear to me firsthand that your XML contains more elements and that you explicitly need the track element with a specific type attribute. You should use xpath for attribute conditions. – hakre Mar 09 '13 at 09:10
  • Note that using XPath in this way you will have to have separate loops for each type you want to process. You could instead loop over all tracks and decide what to do based on which type each is. – IMSoP Mar 10 '13 at 21:25
0

The confusion here is between the name and the value of the attribute. The syntax $xml->track['General'] retrieves the value of an attribute with the name "General", e.g. it will obtain "hello" from <track General="hello" />.

In your case, though, "General" is the value of an attribute with the name type: <track type="General">. So if you want to tell whether a particular track is of type "General", you need to use if ( $xml->track['type'] == 'General' ).

I am also assuming that your file will have many track elements in, so you need to loop over them, just like you would if they were in an array: foreach ( $xml->track as $track ); if there are multiple <File> elements inside the <MediaInfo> container, you wlil need two nested loops. (If you don't do this, you will only ever be looking at the first <File>, and the first <track>.)

So taking the three "types" you show in your example, your code should end up something like this:

$lib  = simplexml_load_file("media.xml");
foreach ( $lib->File as $file )
{
    foreach ( $file->track as $track )
    {
        switch ( (string)$track['type'] )
        {
            case 'General':
                $format = $gen->Format;
                $app = $gen->Encoded_Application;
                $size = $gen->FileSize_String;
                $dur = $gen->Duration_String;
            break;
            case 'Video':
                $vformat = $vid->Format;
                $vbit = $vid->BitRate_Nominal_String;
                $width = $vid->Width_String;
                $height = $vid->Height_String;
                $aspect = $vid->DisplayAspectRatio_String;
                $frame = $vid->FrameRate_String;
                $encode = $vid->Encoded_Library_String;
                $encodes = $vid->Encoded_Library_Settings;
            break;
            case 'Audio':
                $aformat = $aud->Format;
                $compress = $aud->Compression_Mode_String;
                $lang = $aud->Language_String;
            break;
        }
    }
}
IMSoP
  • 89,526
  • 13
  • 117
  • 169
-1

try this

$doc = new DOMDocument();
$doc->load('media.xml');
$xpd = new DOMXPath($doc);
false&&$node = new DOMElement();
$result = $xpd->query('//File/track[@type="General"]/UniqueID_String'); // your path
foreach($result as $node){
    echo $node->nodeName ." => ". $node->nodeValue ."<br/>";
}
M.I.T.
  • 1,040
  • 2
  • 17
  • 34
  • Which IDE are you using? You might be looking for a more common comment that hints the variable type in most IDEs: http://stackoverflow.com/a/1798793/367456 – hakre Mar 09 '13 at 08:45