<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>VSSCORM &#187; Content Aggregation Model</title>
	<atom:link href="http://www.vsscorm.net/category/scorm-cam/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.vsscorm.net</link>
	<description>A Very Simple SCORM Interface</description>
	<lastBuildDate>Thu, 08 Sep 2011 14:45:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>A Simple SCORM 1.2 Content Package</title>
		<link>http://www.vsscorm.net/2010/01/20/a-simple-scorm-1-2-content-package/</link>
		<comments>http://www.vsscorm.net/2010/01/20/a-simple-scorm-1-2-content-package/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 19:11:56 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>
		<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1212</guid>
		<description><![CDATA[If you want a very simple test case, you can use this content package &#8211; a single SCO consisting of: a title page; 3 test questions (the correct answer in each case is &#8220;true&#8221;); and a results page. It was &#8230; <a href="http://www.vsscorm.net/2010/01/20/a-simple-scorm-1-2-content-package/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>If you want a <b>very</b> simple test case, you can use this content package &#8211; a single SCO consisting of:</p>
<ul>
<li>a title page;</li>
<li>3 test questions (the correct answer in each case is &#8220;true&#8221;); and</li>
<li>a results page.</li>
</ul>
<p><span id="more-1212"></span></p>
<p><a href="http://www.vsscorm.net/wp-content/uploads/2010/01/simpletest.gif"><img src="http://www.vsscorm.net/wp-content/uploads/2010/01/simpletest.gif" alt="" title="simpletest" width="600" height="440" class="aligncenter size-full wp-image-1220" /></a></p>
<p>It was created using Lectora, runs in a 760 x 550 window, and sets &#8216;cmi.core.lesson_status&#8217; to &#8220;passed&#8221; to indicate completion. The SCO entry point is &#8216;a001index.html&#8217;.</p>
<p><center>You can download it from <a href="/docs/SimpleTest.zip">here</a></center></p>
<p>Hope it helps! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/01/20/a-simple-scorm-1-2-content-package/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Download VS SCORM 1.2 Manifest Reader Rev 1.1</title>
		<link>http://www.vsscorm.net/2009/11/30/download-vs-scorm-1-2-manifest-reader-rev-1-1/</link>
		<comments>http://www.vsscorm.net/2009/11/30/download-vs-scorm-1-2-manifest-reader-rev-1-1/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 00:26:05 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1094</guid>
		<description><![CDATA[A reader has identified a problem with Rev 1.0 of the IMS Manifest File Reader which causes the parser to fail when there&#8217;s a resource that doesn&#8217;t have any files associated with it. Rev 1.1 corrects this bug. The only &#8230; <a href="http://www.vsscorm.net/2009/11/30/download-vs-scorm-1-2-manifest-reader-rev-1-1/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A reader has identified a problem with Rev 1.0 of the IMS Manifest File Reader which causes the parser to fail when there&#8217;s a resource that doesn&#8217;t have any files associated with it. Rev 1.1 corrects this bug. The only changes are to the resolveIMSManifestDependencies() function in <b>subs.php</b>, and deal with the case where $file is not an array. </p>
<p><center><br />
<table cellpadding=15 cellspacing=0 border=2>
<tr>
<td valign=top align=center>You can download the code bundle using <a href="/docs/vsscorm_cam12_1_1.zip">this link</a>.</td>
</tr>
</table>
<p>&nbsp;</center></p>
<p>All other details &#8211; including system requirements &#8211; are the same as for <a href="/2009/11/07/download-vs-scorm-1-2-manifest-reader-rev-1-0/">Rev 1.0.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/11/30/download-vs-scorm-1-2-manifest-reader-rev-1-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Download VS SCORM 1.2 Manifest Reader Rev 1.0</title>
		<link>http://www.vsscorm.net/2009/11/07/download-vs-scorm-1-2-manifest-reader-rev-1-0/</link>
		<comments>http://www.vsscorm.net/2009/11/07/download-vs-scorm-1-2-manifest-reader-rev-1-0/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 14:28:58 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=943</guid>
		<description><![CDATA[This code bundle is a LOT simpler than the bundle for the VSSCORM 1.2 RTE (Run-Time Environment) that I posted a couple of months ago. It consists of 2 files: subs.php which contains all of the code that does the &#8230; <a href="http://www.vsscorm.net/2009/11/07/download-vs-scorm-1-2-manifest-reader-rev-1-0/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This code bundle is a LOT simpler than the bundle for the <a href="/2009/08/19/download-vs-scorm-1-2-rte-rev-1-0/">VSSCORM 1.2 RTE (Run-Time Environment)</a> that I posted a couple of months ago. It consists of 2 files:</p>
<ul>
<li><strong>subs.php</strong> which contains all of the code that does the parsing and analysis of the manifest file
<li><strong>index.php</strong> which simply provides you with a way to run the code and display the output in a test environment
</ul>
<p>In other words, if you wanted to incorporate the code into a real system, you would only need the content of subs.php.</p>
<p>The system requirements for running this code are pretty simple &#8211; you just need to have PHP 5 or above (PHP 4 doesn&#8217;t support the DOM extension that I&#8217;m using to parse the XML manifest file).</p>
<p>To help you get started, I&#8217;ve also included the 2 sample manifest files that I&#8217;ve been using.</p>
<p><center><br />
<table cellpadding=15 cellspacing=0 border=2>
<tr>
<td valign=top align=center>You can download the code bundle using <a href="/docs/vsscorm_cam12_1_0.zip">this link</a>.</td>
</tr>
</table>
<p>&nbsp;</center></p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/11/07/download-vs-scorm-1-2-manifest-reader-rev-1-0/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Step 42 &#8211; Testing the Manifest File Reader</title>
		<link>http://www.vsscorm.net/2009/11/06/step-42-testing-the-manifest-file-reader/</link>
		<comments>http://www.vsscorm.net/2009/11/06/step-42-testing-the-manifest-file-reader/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 19:19:01 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=932</guid>
		<description><![CDATA[Time to see if everything works. I&#8217;m going to test my code using two different manifest files: A single SCO manifest file created by Captivate &#8211; [download manifest file] A multiple SCO manifest file that I created using Lectora &#8211; &#8230; <a href="http://www.vsscorm.net/2009/11/06/step-42-testing-the-manifest-file-reader/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Time to see if everything works. I&#8217;m going to test my code using two different manifest files:</p>
<ul>
<li>A single SCO manifest file created by <a href="http://www.adobe.com/devnet/captivate/articles/output_scorm.html" target="_blank">Captivate</a> &#8211; [<a href="/docs/single-sco_imsmanifest.xml" target="_blank">download manifest file</a>]
<li>A multiple SCO manifest file that I created using <a href="http://www.lectora.com" target="_blank">Lectora</a> &#8211; [<a href="/docs/multiple-sco_imsmanifest.xml" target="_blank">download manifest file</a>]
</ul>
<p>To be honest, I don&#8217;t think I&#8217;ve ever come across a multiple-SCO content package in a real application, but I do need to be able to handle it if I do stumble across it.</p>
<p><span id="more-932"></span></p>
<p>So let&#8217;s try the single SCO manifest file. When I run my manifest file reader, I get the following output.</p>
<p><center><br />
<table cellpadding=3 cellspacing=0 border=1>
<tr>
<td valign=top align=left><b>Identifier</b></td>
<td valign=top align=left><b>Title</b></td>
<td valign=top align=left><b>MasteryScore</b></td>
<td valign=top align=left><b>LaunchData</b></td>
<td valign=top align=left><b>SCO Entry Point</b></td>
<td valign=top align=left><b>Required Files</b></td>
</tr>
<tr>
<td valign=top align=left>P1</td>
<td valign=top align=left>Browser Options</td>
<td valign=top align=left>80</td>
<td valign=top align=left>&nbsp;</td>
<td valign=top align=left>Simulation.htm</td>
<td valign=top align=left>Simulation.swf<br />Simulation.htm<br />SCORM_support/scorm_support.htm<br />SCORM_support/scorm_support.js<br />SCORM_support/scorm_support.swf</td>
</tr>
</table>
<p></center></p>
<p>This is what I&#8217;d expect from a manual analysis of the manifest file. So far, so good.</p>
<p>Now the multiple SCO manifest file. This is more challenging since, if you look at the manifest file itself, you can see that there are a host of linked resources, and that a number of the resources are shared by the two SCOs. So let&#8217;s give it a try &#8211; here&#8217;s what I get.</p>
<p><center><br />
<table cellpadding=3 cellspacing=0 border=1>
<tr>
<td valign=top align=left><b>Identifier</b></td>
<td valign=top align=left><b>Title</b></td>
<td valign=top align=left><b>MasteryScore</b></td>
<td valign=top align=left><b>LaunchData</b></td>
<td valign=top align=left><b>SCO Entry Point</b></td>
<td valign=top align=left><b>Required Files</b></td>
</tr>
<tr>
<td valign=top align=left>I_A001</td>
<td valign=top align=left>A001</td>
<td valign=top align=left>75</td>
<td valign=top align=left>&nbsp;</td>
<td valign=top align=left>a001index.html</td>
<td valign=top align=left>a001index.html<br />a001content.html<br />a001titlemgr.html<br />a001_page_1.html<br />a001_page_2.html<br />images/backoff.gif<br />images/backclk.gif<br />images/backrol.gif<br />images/homeoff.gif<br />images/homeclk.gif<br />images/homerol.gif<br />images/nextoff.gif<br />images/nextclk.gif<br />images/nextrol.gif<br />images/dlg-titlebar.gif<br />images/dlg-close.gif<br />apiwrapper11.js<br />scofunctions.js<br />trivantis.css<br />dialog.css<br />trivantis.js<br />trivantis-timedate.js<br />trivantis-cookie.js<br />trivantis-dialog.js<br />trivantis-button.js<br />trivantis-inline.js<br />trivantis-titlemgr.js<br />trivantis-strings.js<br />a001_page_3.html<br />a001_page_4.html<br />a001_page_5.html<br />a001_test_a001_page_4.html<br />images/std_qt_canceloff.gif<br />images/std_qt_cancelclk.gif<br />images/std_qt_cancelrol.gif<br />images/std_qt_backoff.gif<br />images/std_qt_backclk.gif<br />images/std_qt_backrol.gif<br />images/std_qt_nextoff.gif<br />images/std_qt_nextclk.gif<br />images/std_qt_nextrol.gif<br />_tobj23.xml<br />a001_test_a001_page_3.html<br />a001_test_a001_page_1.html<br />a001_test_a001_last_test_page.html<br />images/std_qt_doneoff.gif<br />images/std_qt_doneclk.gif<br />images/std_qt_donerol.gif</td>
</tr>
<tr>
<td valign=top align=left>I_A002</td>
<td valign=top align=left>A002</td>
<td valign=top align=left>95</td>
<td valign=top align=left>&nbsp;</td>
<td valign=top align=left>a002index.html</td>
<td valign=top align=left>a002index.html<br />a002content.html<br />a002titlemgr.html<br />a002_page_1.html<br />a002_page_2.html<br />images/backoff.gif<br />images/backclk.gif<br />images/backrol.gif<br />images/homeoff.gif<br />images/homeclk.gif<br />images/homerol.gif<br />images/nextoff.gif<br />images/nextclk.gif<br />images/nextrol.gif<br />images/dlg-titlebar.gif<br />images/dlg-close.gif<br />apiwrapper11.js<br />scofunctions.js<br />trivantis.css<br />dialog.css<br />trivantis.js<br />trivantis-timedate.js<br />trivantis-cookie.js<br />trivantis-dialog.js<br />trivantis-button.js<br />trivantis-inline.js<br />trivantis-titlemgr.js<br />trivantis-strings.js<br />a002_page_3.html<br />a002_page_4.html<br />a002_page_5.html<br />a002_test_a002_page_3.html<br />images/std_qt_canceloff.gif<br />images/std_qt_cancelclk.gif<br />images/std_qt_cancelrol.gif<br />images/std_qt_backoff.gif<br />images/std_qt_backclk.gif<br />images/std_qt_backrol.gif<br />images/std_qt_nextoff.gif<br />images/std_qt_nextclk.gif<br />images/std_qt_nextrol.gif<br />_tobj42.xml<br />a002_test_a002_page_1.html<br />a002_test_a002_last_test_page.html<br />images/std_qt_doneoff.gif<br />images/std_qt_doneclk.gif<br />images/std_qt_donerol.gif</td>
</tr>
</table>
<p></center></p>
<p>A lot more complicated but, comparing the output with the manifest file, it would certainly seem that I&#8217;ve successfully disentangled all of the dependencies, and identified the two SCOs.</p>
<p>All looking pretty good so far. Tomorrow I&#8217;ll post a copy of the manifest file reader code for you to download and play with.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/11/06/step-42-testing-the-manifest-file-reader/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 41 &#8211; SCO Data = Item Data + Resource Data</title>
		<link>http://www.vsscorm.net/2009/10/30/step-41-sco-data-item-data-resource-data/</link>
		<comments>http://www.vsscorm.net/2009/10/30/step-41-sco-data-item-data-resource-data/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 15:48:51 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=923</guid>
		<description><![CDATA[Finally, I&#8217;ll add the code which connects the item and resource data together to create the data that the &#8220;imaginary&#8221; LMS needs. // array for the results $SCOdata = array(); // loop through the list of items foreach ($itemData as &#8230; <a href="http://www.vsscorm.net/2009/10/30/step-41-sco-data-item-data-resource-data/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Finally, I&#8217;ll add the code which connects the item and resource data together to create the data that the &#8220;imaginary&#8221; LMS needs.</p>
<p><span id="more-923"></span></p>
<pre class="brush:php; first-line: 1">  // array for the results
  $SCOdata = array();

  // loop through the list of items
  foreach ($itemData as $identifier => $item) {

    // find the linked resource
    $identifierref = $item['identifierref'];

    // is the linked resource a SCO? if not, skip this item
    if (strtolower($resourceData[$identifierref]['scormtype']) != 'sco') { continue; }

    // save data that we want to the output array
    $SCOdata[$identifier]['title'] = $item['title'];
    $SCOdata[$identifier]['masteryscore'] = $item['masteryscore'];
    $SCOdata[$identifier]['datafromlms'] = $item['datafromlms'];
    $SCOdata[$identifier]['href'] = $resourceData[$identifierref]['href'];
    $SCOdata[$identifier]['files'] = $resourceData[$identifierref]['files'];

  }</pre>
<p>Next post &#8230; I&#8217;ll run some tests, and post a full copy of the code for you to download if you want to try it out for yourself.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/30/step-41-sco-data-item-data-resource-data/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Step 40 &#8211; Reading the Items List</title>
		<link>http://www.vsscorm.net/2009/10/28/step-40-reading-the-items-list/</link>
		<comments>http://www.vsscorm.net/2009/10/28/step-40-reading-the-items-list/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 15:24:16 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=914</guid>
		<description><![CDATA[At last, an easy bit. I&#8217;m going to add the following code to my readIMSManifestFile() function. // array to store the results $itemData = array(); // get the list of item elements $itemList = $xmlfile->getElementsByTagName('item'); $i = 0; foreach ($itemList &#8230; <a href="http://www.vsscorm.net/2009/10/28/step-40-reading-the-items-list/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>At last, an easy bit. I&#8217;m going to add the following code to my readIMSManifestFile() function.</p>
<p><span id="more-914"></span></p>
<pre class="brush:php; first-line: 1; html-script: false">  // array to store the results
  $itemData = array();

  // get the list of item elements
  $itemList = $xmlfile->getElementsByTagName('item');

  $i = 0;
  foreach ($itemList as $itemp) {

    // decode the item attributes and sub-elements
    $identifier = $itemList->item($i)->getAttribute('identifier');
    $itemData[$identifier]['identifierref'] = $itemList->item($i)->getAttribute('identifierref');
    $itemData[$identifier]['title'] = $itemList->item($i)->getElementsByTagName('title')->item(0)->nodeValue;
    $itemData[$identifier]['masteryscore'] = $itemList->item($i)->getElementsByTagNameNS($adlcp,'masteryscore')->item(0)->nodeValue;
    $itemData[$identifier]['datafromlms'] = $itemList->item($i)->getElementsByTagNameNS($adlcp,'datafromlms')->item(0)->nodeValue;

    $i++;

  }</pre>
<p>This will read the item data from the manifest file into a new array called $itemData. Next step &#8230; combine the resource and item data to give me the information that I need for my &#8220;imaginary&#8221; LMS.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/28/step-40-reading-the-items-list/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Step 39 &#8211; Resolving Resource Dependencies</title>
		<link>http://www.vsscorm.net/2009/10/26/step-39-resolving-resource-dependencies/</link>
		<comments>http://www.vsscorm.net/2009/10/26/step-39-resolving-resource-dependencies/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 15:12:13 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=904</guid>
		<description><![CDATA[This is the new routine that I&#8217;m going to use to resolve the resource dependencies in the package manifest file. function resolveIMSManifestDependencies($identifier) { global $resourceData; $files = $resourceData[$identifier]['files']; $dependencies = $resourceData[$identifier]['dependencies']; if (is_array($dependencies)) { foreach ($dependencies as $d => $dependencyidentifier) &#8230; <a href="http://www.vsscorm.net/2009/10/26/step-39-resolving-resource-dependencies/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is the new routine that I&#8217;m going to use to resolve the resource dependencies in the package manifest file.</p>
<p><span id="more-904"></span></p>
<pre class="brush:php; first-line: 1">function resolveIMSManifestDependencies($identifier) {

  global $resourceData;

  $files = $resourceData[$identifier]['files'];

  $dependencies = $resourceData[$identifier]['dependencies'];
  if (is_array($dependencies)) {
    foreach ($dependencies as $d => $dependencyidentifier) {
      $files = array_merge($files,resolveIMSManifestDependencies($dependencyidentifier));
      unset($resourceData[$identifier]['dependencies'][$d]);
    }
    $files = array_unique($files);
  }

  return $files;

}</pre>
<p>Here&#8217;s what I&#8217;m doing &#8211; line-by-line:</p>
<ul>
<li><b>Line 1</b>: The function takes a resource identifier as its argument.<br />&nbsp;</li>
<li><b>Line 3</b>: I&#8217;m going to process the data that I&#8217;ve stored in the $resourceData array, so I make it a global variable. I&#8217;ll have to do the same in the readIMSManifestFile() function, but more of that later.<br />&nbsp;</li>
<li><b>Line 5</b>: I read the existing list of files for this resource (see line 1) into an array. I&#8217;ll be updating this as I go through the function.<br />&nbsp;</li>
<li><b>Line 7</b>: I read the dependency information for this resource into an array called $dependencies.<br />&nbsp;</li>
<li><b>Lines 8 through 14</b>: I loop through each of the dependencies for this resource.<br />&nbsp;</li>
<li><b>Line 10</b>: This is the line that does the hard work. What I do is to merge together my existing &#8216;files&#8217; array with a new &#8216;files&#8217; array that I create by recursively calling the resolveIMSManifestDependencies() for each dependency (and any of its dependencies).<br />&nbsp;</li>
<li><b>Line 11</b>: Since I&#8217;ve resolved this dependency (and any of its dependencies), I unset the dependency data in the $resourceData array so that I don&#8217;t process it again.<br />&nbsp;</li>
<li><b>Line 13</b>: I eliminate any duplicate entries in the &#8216;files&#8217; array.<br />&nbsp;</li>
<li><b>Line 16</b>: I return the &#8216;files&#8217; array to the calling program.<br />&nbsp;</li>
</ul>
<p>Now I have to modify the readIMSManifestFile() function so that it looks like this.</p>
<pre class="brush:php; first-line: 1">function readIMSManifestFile($manifestfile) {

  // PREPARATIONS

  // central array for resource data
  global $resourceData;

  // load the imsmanifest.xml file
  $xmlfile = new DomDocument;
  $xmlfile->preserveWhiteSpace = FALSE;
  $xmlfile->load($manifestfile);

  // adlcp namespace
  $manifest = $xmlfile->getElementsByTagName('manifest');
  $adlcp = $manifest->item(0)->getAttribute('xmlns:adlcp');

  // READ THE RESOURCES LIST

  // array to store the results
  $resourceData = array();

  // get the list of resource element
  $resourceList = $xmlfile->getElementsByTagName('resource');

  $r = 0;
  foreach ($resourceList as $rtemp) {

    // decode the resource attributes
    $identifier = $resourceList->item($r)->getAttribute('identifier');
    $resourceData[$identifier]['type'] = $resourceList->item($r)->getAttribute('type');
    $resourceData[$identifier]['scormtype'] = $resourceList->item($r)->getAttribute('adlcp:scormtype');
    $resourceData[$identifier]['href'] = $resourceList->item($r)->getAttribute('href');

    // list of files
    $fileList = $resourceList->item($r)->getElementsByTagName('file');

    $f = 0;
    foreach ($fileList as $ftemp) {
      $resourceData[$identifier]['files'][$f] =  $fileList->item($f)->getAttribute('href');
      $f++;
    }

    // list of dependencies
    $dependencyList = $resourceList->item($r)->getElementsByTagName('dependency');

    $d = 0;
    foreach ($dependencyList as $dtemp) {
      $resourceData[$identifier]['dependencies'][$d] =  $dependencyList->item($d)->getAttribute('identifierref');
      $d++;
    }

    $r++;

  }

  // resolve resource dependencies to create the file lists for each resource
  foreach ($resourceData as $identifier => $resource) {
    $resourceData[$identifier]['files'] = resolveIMSManifestDependencies($identifier);
  }

  // READ THE ITEMS LIST

  // PROCESS THE ITEMS LIST TO FIND SCOS

  // RETURN RESULTS

}</pre>
<p>The changes are:</p>
<ul>
<li><b>Line 6</b>: I make the $resourceData array &#8211; a working array where I store all of the information as I process it &#8211; global so that it&#8217;s accessible to the resolveIMSManifestDependencies() function.<br />&nbsp;</li>
<li><b>Lines 44 to 49</b>: I create a list of dependencies for each resource, and save it into the $resourceData array.<br />&nbsp;</li>
<li><b>Lines 56 to 59</b>: After I&#8217;ve read all of the data for the resources (the loop finishes on line 54) I loop through the list of resources again and resolve all of the dependencies by calling resolveIMSManifestDependencies() as I described above.<br />&nbsp;</li>
</ul>
<p>Now that I&#8217;ve read all of the resources data, I&#8217;m going to read the items data. That will be my next post.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/26/step-39-resolving-resource-dependencies/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 38 &#8211; Revisiting the Manifest File Format</title>
		<link>http://www.vsscorm.net/2009/10/22/step-38-revisiting-the-manifest-file-format/</link>
		<comments>http://www.vsscorm.net/2009/10/22/step-38-revisiting-the-manifest-file-format/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 22:33:03 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=890</guid>
		<description><![CDATA[I&#8217;m going to re-examine the XML format that the SCORM 1.2 CAM specifies for the manifest file. As a reminder, here&#8217;s the &#60;resource&#62; tag that I&#8217;m trying to understand. The CAM specification defines the XML format for the &#60;resource&#62; tag &#8230; <a href="http://www.vsscorm.net/2009/10/22/step-38-revisiting-the-manifest-file-format/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to re-examine the XML format that the SCORM 1.2 CAM specifies for the manifest file. As a reminder, here&#8217;s the &lt;resource&gt; tag that I&#8217;m trying to understand.</p>
<p><span id="more-890"></span></p>
<pre class="brush:xml; first-line: 1; smart-tabs: false"><resource identifier="P_10" type="webcontent" adlcp:scormtype="asset">
  <file href="a001_page_3.html"></file>
  <dependency identifierref="R_2"></dependency>
  <dependency identifierref="R_4"></dependency>
  <dependency identifierref="R_6"></dependency>
  <dependency identifierref="S_DLGFiles"></dependency>
  <dependency identifierref="S_SCORMFiles"></dependency>
  <dependency identifierref="S_BaseFiles"></dependency>
</resource></pre>
<p>The CAM specification defines the XML format for the &lt;resource&gt; tag like this.</p>
<p><img src="http://www.vsscorm.net/wp-content/uploads/2009/10/resource_tag.gif" alt="resource_tag" title="resource_tag" width="540" height="202" class="aligncenter size-full wp-image-894" /></p>
<p>What does this mean? That each &lt;resource&gt; tag contains:</p>
<table cellpadding=5 cellspacing=0 border=1>
<tr>
<td colspan=4 align=center><b>Attributes</b></td>
</tr>
<tr>
<td valign=top align=left>identifier</td>
<td valign=top align=left>A unique reference code for this resource.</td>
<td valign=top align=left>Mandatory</td>
<td valign=top align=left>One Only</td>
</tr>
<tr>
<td valign=top align=left>type</td>
<td valign=top align=left>Identifies the type of resource. SCORM 1.2 only supports one value for this attribute &#8211; &#8220;webcontent&#8221;.</td>
<td valign=top align=left>Mandatory</td>
<td valign=top align=left>One Only</td>
</tr>
<tr>
<td valign=top align=left>adlcp:scormtype</td>
<td valign=top align=left>Identifies the type of SCORM content. SCORM 1.2 only supports two values for this attribute &#8211; &#8220;sco&#8221; or &#8220;asset&#8221;.</td>
<td valign=top align=left>Mandatory</td>
<td valign=top align=left>One Only</td>
</tr>
<tr>
<td valign=top align=left>href</td>
<td valign=top align=left>A URL pointing to the &#8216;entry point&#8217; for this resource.</td>
<td valign=top align=left>Mandatory</td>
<td valign=top align=left>One Only</td>
</tr>
<tr>
<td valign=top align=left>xml:base</td>
<td valign=top align=left>A relative path offset for the content file.</td>
<td valign=top align=left>Optional</td>
<td valign=top align=left>None or One</td>
</tr>
<tr>
<td colspan=4 align=center><b>Elements</b></td>
</tr>
<tr>
<td valign=top align=left>metadata</td>
<td valign=top align=left>Data describing the resource.</td>
<td valign=top align=left>Optional</td>
<td valign=top align=left>None or One</td>
</tr>
<tr>
<td valign=top align=left>file</td>
<td valign=top align=left>Location (URL) for a file within the package.</td>
<td valign=top align=left>Optional</td>
<td valign=top align=left>None, One, or Many</td>
</tr>
<tr>
<td valign=top align=left>dependency</td>
<td valign=top align=left>Reference to another resource that may contain references to further files and/or resources.</td>
<td valign=top align=left>Optional</td>
<td valign=top align=left>None, One, or Many</td>
</tr>
</table>
<p>So, to create a simple example, we might have a structure like this.</p>
<pre class="brush:xml; first-line: 1; smart-tabs: false;"><resource identifier="RES01" type="webcontent" adlcp:scormtype="sco" href="myfile01.htm">
  <file href="myfile01.htm"></file>
  <file href="myfile02.gif"></file>
  <dependency identifierref="RES02"></dependency>
  <dependency identifierref="RES03"></dependency>
</resource>

<resource identifier="RES02" type="webcontent" adlcp:scormtype="asset">
  <file href="data/myfile03.txt"></file>
</resource>

<resource identifier="RES03" type="webcontent" adlcp:scormtype="asset">
  <file href="data/myfile04.txt"></file>
  <dependency identifierref="RES04"></dependency>
</resource>

<resource identifier="RES04" type="webcontent" adlcp:scormtype="asset">
  <file href="scripts/myfile05.js"></file>
  <file href="scripts/myfile06.js"></file>
  <file href="scripts/myfile07.js"></file>
  <file href="scripts/myfile08.js"></file>
</resource></pre>
<p>When I resolve all of the dependencies, the list of files that I need for the SCO identified as &#8216;RES01&#8242; is as follows:</p>
<pre>&nbsp;&nbsp;&nbsp;myfile01.htm
&nbsp;&nbsp;&nbsp;myfile02.gif
&nbsp;&nbsp;&nbsp;data/myfile03.txt
&nbsp;&nbsp;&nbsp;data/myfile04.txt
&nbsp;&nbsp;&nbsp;scripts/myfile05.js
&nbsp;&nbsp;&nbsp;scripts/myfile06.js
&nbsp;&nbsp;&nbsp;scripts/myfile07.js
&nbsp;&nbsp;&nbsp;scripts/myfile08.js</pre>
<p>where &#8216;myfile01.htm&#8217; is the entry point for the SCO. Next time &#8230; code to process the dependencies.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/22/step-38-revisiting-the-manifest-file-format/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 37 &#8211; The readIMSManifest Function</title>
		<link>http://www.vsscorm.net/2009/10/21/step-37-the-readimsmanifest-function/</link>
		<comments>http://www.vsscorm.net/2009/10/21/step-37-the-readimsmanifest-function/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 17:23:57 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=869</guid>
		<description><![CDATA[Time to start writing the readIMSManifestFile() function. Let&#8217;s create the basic structure. function readIMSManifestFile($manifestfile) { // PREPARATIONS // READ THE RESOURCES LIST // READ THE ITEMS LIST // PROCESS THE ITEMS LIST TO FIND SCOS // RETURN RESULTS } The &#8230; <a href="http://www.vsscorm.net/2009/10/21/step-37-the-readimsmanifest-function/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Time to start writing the readIMSManifestFile() function. Let&#8217;s create the basic structure.</p>
<p><span id="more-869"></span></p>
<pre class="brush:php; first-line: 1; html-script: false">function readIMSManifestFile($manifestfile) {

  // PREPARATIONS

  // READ THE RESOURCES LIST

  // READ THE ITEMS LIST

  // PROCESS THE ITEMS LIST TO FIND SCOS

  // RETURN RESULTS

}</pre>
<p>The first section is pretty straightforward since I can build on the code that I created <a href="/2009/10/05/step-34-reading-the-ims-manifest-file/">previously</a>.</p>
<pre class="brush:php; first-line: 1; html-script: false">  // PREPARATIONS

  // load the imsmanifest.xml file
  $xmlfile = new DomDocument;
  $xmlfile->preserveWhiteSpace = FALSE;
  $xmlfile->load($manifestfile);

  // adlcp namespace
  $manifest = $xmlfile->getElementsByTagName('manifest');
  $adlcp = $manifest->item(0)->getAttribute('xmlns:adlcp');</pre>
<p>I start by loading the manifest file into a variable, and I read the XML namespace definitions that I need.</p>
<p>Now I move on to reading the resources list. Here&#8217;s my initial code. </p>
<pre class="brush:php; first-line: 1; html-script: false">  // READ THE RESOURCES LIST

  // array to store the results
  $resourceData = array();

  // get the list of resource element
  $resourceList = $xmlfile->getElementsByTagName('resource');

  $r = 0;
  foreach ($resourceList as $rtemp) {

    // decode the resource attributes
    $identifier = $resourceList->item($r)->getAttribute('identifier');
    $resourceData[$identifier]['type'] = $resourceList->item($r)->getAttribute('type');
    $resourceData[$identifier]['scormtype'] = $resourceList->item($r)->getAttribute('adlcp:scormtype');
    $resourceData[$identifier]['href'] = $resourceList->item($r)->getAttribute('href');

    // list of files
    $fileList = $resourceList->item($r)->getElementsByTagName('file');

    $f = 0;
    foreach ($fileList as $ftemp) {
      $resourceData[$identifier]['files'][$f] =  $fileList->item($f)->getAttribute('href');
      $f++;
    }

    $r++;

  }</pre>
<p>Pretty much as I did before, but this time I&#8217;m storing the data that I read in the $resourceData array. Let&#8217;s look at the XML file that I&#8217;m reading to see if I&#8217;m capturing all of the data. Here&#8217;s a typical &lt;resource&gt; element.</p>
<pre class="brush:xml; first-line: 1;"><resource identifier="P_10" type="webcontent" adlcp:scormtype="asset">
  <file href="a001_page_3.html"></file>
  <dependency identifierref="R_2"></dependency>
  <dependency identifierref="R_4"></dependency>
  <dependency identifierref="R_6"></dependency>
  <dependency identifierref="S_DLGFiles"></dependency>
  <dependency identifierref="S_SCORMFiles"></dependency>
  <dependency identifierref="S_BaseFiles"></dependency>
</resource></pre>
<p>Whoops &#8230; whereas the IMS manifest file that I was reading <a href="/2009/10/05/step-34-reading-the-ims-manifest-file/">previously</a> had a single resource which contained multiple files, this manifest file consists of multiple &lt;resource&gt; elements which appear to be linked together by &lt;dependency&gt; elements. So I&#8217;m going to have to take a step backward and look at the SCORM 1.2 CAM specification again in far more detail.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/21/step-37-the-readimsmanifest-function/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 36 &#8211; Rewriting the Manifest Reader</title>
		<link>http://www.vsscorm.net/2009/10/13/step-36-rewriting-the-manifest-reader/</link>
		<comments>http://www.vsscorm.net/2009/10/13/step-36-rewriting-the-manifest-reader/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 08:00:10 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Content Aggregation Model]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=867</guid>
		<description><![CDATA[In my last two posts, I figured out how to read resource and organization data from the manifest file that describes the content package. But the code that I wrote really wasn&#8217;t that solid, and wouldn&#8217;t be particularly easy to &#8230; <a href="http://www.vsscorm.net/2009/10/13/step-36-rewriting-the-manifest-reader/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In my last two posts, I figured out how to read resource and organization data from the manifest file that describes the content package. But the code that I wrote really wasn&#8217;t that solid, and wouldn&#8217;t be particularly easy to integrate with my &#8220;imaginary&#8221; LMS. So I&#8217;m going to take the lessons that I learned there and see if I can create something a little better.</p>
<p><span id="more-867"></span></p>
<p>In <a href="/2009/08/10/step-26-getting-data-from-the-lms/">Step 26 (Getting Data from the LMS)</a>, I identified that my RTE needed the following parameters to run &#8211; three of which come from the data in the imsmanifest file:</p>
<p><center><br />
<table cellpadding=5 cellspacing=0 border=1>
<tr>
<td valign=top align=left><b>Parameter</b></td>
<td valign=top align=left><b>Data From</b></td>
<td valign=top align=left><b>Used In</b></td>
</tr>
<tr bgcolor="#FFFFCC">
<td valign=top align=left>the entry point for the SCO</td>
<td valign=top align=left>imsmanifest file</td>
<td valign=top align=left>rte.php</td>
</tr>
<tr>
<td valign=top align=left>cmi.core.student_name</td>
<td valign=top align=left>the LMS database</td>
<td valign=top align=left>initialize.php</td>
</tr>
<tr>
<td valign=top align=left>cmi.core.student_id</td>
<td valign=top align=left>the LMS database</td>
<td valign=top align=left>initialize.php</td>
</tr>
<tr bgcolor="#FFFFCC">
<td valign=top align=left>adlcp:masteryscore</td>
<td valign=top align=left>imsmanifest file</td>
<td valign=top align=left>initialize.php</td>
</tr>
<tr bgcolor="#FFFFCC">
<td valign=top align=left>cmi.launch_data</td>
<td valign=top align=left>imsmanifest file</td>
<td valign=top align=left>initialize.php</td>
</tr>
</table>
<p></center></p>
<p>And I&#8217;m going to add a couple more that will probably be needed by a typical LMS:</p>
<ol>
<li>I&#8217;m going to extract the SCO title from the manifest file as well, because I&#8217;m sure that a real LMS would need to use it in a listing screen.<br />&nbsp;
<li>The manifest file contains a list of files that constitute the resources. This would (probably) be useful for the LMS to know when importing a package so that it could extract only those files that it needs to run the SCO. This might not be quite as important right now, with disk space being so cheap, but I&#8217;ll include it anyway.
</ol>
<p>So, the data that I want from the manifest file is:</p>
<ol>
<li>the SCO title
<li>the mastery score set in the manifest file
<li>the launch data for the SCO
<li>the entry point for the SCO
<li>a list of files
</ol>
<p>I&#8217;m going to create a function called readIMSManifestFile($manifestfile) which, given the path to the manifest file on disk, will return the data that I require in an array e.g.</p>
<pre class="brush:php; first-line: 1; html-script: false;">$SCOdata = readIMSManifestFile("/data/import/123/imsmanifest.xml");</pre>
<p>This should be easier to integrate with LMS code. To test it out, I create a short PHP/HTML program like this:</p>
<pre class="brush:php; first-line: 1; html-script: false;">&lt;?php 

/*

VS SCORM - CAM - index.php
Rev 2.0 - Monday, October 12, 2009
Copyright (C) 2009, Addison Robson LLC

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA  02110-1301, USA.

*/

require "subs.php";
$SCOdata = readIMSManifestFile('imsmanifest.xml');

// ------------------------------------------------------------------------------------
// Process the Items List to Find SCOs
// ------------------------------------------------------------------------------------

// output table header row
$SCOListTable  = "&lt;table cellpadding=3 cellspacing=0 border=1>\n";
$SCOListTable .= "&lt;tr>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>Identifier&lt;/b>&lt;/td>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>Title&lt;/b>&lt;/td>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>MasteryScore&lt;/b>&lt;/td>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>LaunchData&lt;/b>&lt;/td>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>SCO Entry Point&lt;/b>&lt;/td>\n";
$SCOListTable .= "\t&lt;td valign=top align=left>&lt;b>Required Files&lt;/b>&lt;/td>\n";
$SCOListTable .= "&lt;/tr>\n";

// loop through the list of items
foreach ($SCOdata as $identifier => $SCO) {

	// data that we want
	$SCOListTable .= "&lt;tr>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".cleanVar($identifier)."&lt;/td>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".cleanVar($SCO['title'])."&lt;/td>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".cleanVar($SCO['masteryscore'])."&lt;/td>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".cleanVar($SCO['datafromlms'])."&lt;/td>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".cleanVar($SCO['href'])."&lt;/td>\n";
	$SCOListTable .= "\t&lt;td valign=top align=left>".implode('&lt;br>',$SCO['files'])."&lt;/td>\n";
	$SCOListTable .= "&lt;/tr>\n";

}

$SCOListTable .= "&lt;/table>\n";

// function to clean data for display
function cleanVar($value) {
  $value = (trim($value) == "") ? "&nbsp;" : htmlentities(trim($value));
  return $value;
}

?>
&lt;html>
&lt;head>
  &lt;title>&lt;/title>
  &lt;style type="text/css">
  p,td,li,body,input,select,textarea {
    font-family: verdana, sans-serif;
    font-size: 10pt;
  }
  h1 {
    font-weight: bold;
    font-size: 12pt;
  }
  &lt;/style>
&lt;/head>
&lt;body bgcolor="#ffffff">

&lt;h1>SCO Data&lt;/h1>
&lt;p>&lt;?php print $SCOListTable; ?>

&lt;body>
&lt;/html></pre>
<p>This program simply requires/includes the &#8216;subs.php&#8217; file that contains the functions that do the actual work, calls the readIMSManifestFile() function, and displays the resulting data in an HTML table.</p>
<p>One further thing to note here &#8212; you&#8217;ll see from the looping construct on lines 45 through 58 that the code is designed to handle multiple SCOs contained in the same content package. Although I&#8217;ve conducted my tests so far using a single SCO package, the SCORM 1.2 CAM specification allows there to be multiple SCOs contained within the same package.</p>
<p>To be quite honest, I&#8217;ve never come across a multiple SCO package in a business environment, but I do have to allow for the possibility. So I&#8217;ve created a test package consisting of 2 SCOs using the Lectora authoring tool. You can download a copy of the imsmanifest file from [<a href="/docs/imsmanifest2.xml" target="_blank">here</a>] if you&#8217;d like to follow along with the next stages.</p>
<p>Next post &#8230; I&#8217;m going to start writing the code for the readIMSManifestFile() function.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2009/10/13/step-36-rewriting-the-manifest-reader/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

