# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: millennium.module
--- millennium.module Base (1.13.2.33.2.2.2.109)
+++ millennium.module Locally Modified (Based On 1.13.2.33.2.2.2.109)
@@ -2548,7 +2548,7 @@
     }
     // Check Drupal's cache
     $cached_data = cache_get($cid);
-    if ($cached_data) {
+    if ($cached_data->data && $cached_data->expire > time()) {
       $cache[$cid] = $cached_data->data;
       return $cache[$cid];
     }
@@ -2564,7 +2564,20 @@
     $fetched_html = $result->data;
   }
 
-  static $code_2_human = array(
+  $items = millennium_parse_holdings_from_html($fetched_html);
+  // Set static cache
+  $cache[$cid] = $items;
+  // Cache for one day
+  cache_set($cid, $items, 'cache', time()+(24*3600));
+  return $items;
+}
+
+/**
+ * Recieves html that contains a holdings table, and returns an array describing
+ * its items.
+ */
+function millennium_parse_holdings_from_html($html) {
+   static $code_2_human = array(
     '1' => 'location',
     '$' => 'location',
     '!' => 'message',
@@ -2574,14 +2587,16 @@
     '#' => 'copy',
     'y' => '????', // TODO: find out what field y is!
   );
+  $items = array();
+
   /*
   -- EXAMPLE 1 --
   <tr  class="bibItemsEntry">
-  <td width="22%" > <!-- field 1 -- >&nbsp; CEM GENERAL
+  <td width="22%" > <!-- field 1 -->&nbsp; CEM GENERAL
   </td>
-  <td width="33%" > <!-- field C -- >&nbsp;<a href="/search*spi/cQA76.76.P37+M49+2007/cqa+++76.76+p37+m49+2007/-3,-1,,E/browse">QA76.76.P37 M49 2007</a>&nbsp; <!-- field v -->&nbsp;&nbsp; <!-- field # -->&nbsp;</td>
-  <td width="22%" > <!-- field ! -- ></td>
-  <td width="23%" > <!-- field % -- >&nbsp; DISPONIBLE</td></tr>
+  <td width="33%" > <!-- field C -->&nbsp;<a href="/search*spi/cQA76.76.P37+M49+2007/cqa+++76.76+p37+m49+2007/-3,-1,,E/browse">QA76.76.P37 M49 2007</a>&nbsp; <!-- field v -->&nbsp;&nbsp; <!-- field # -->&nbsp;</td>
+  <td width="22%" > <!-- field ! --></td>
+  <td width="23%" > <!-- field % -->&nbsp; DISPONIBLE</td></tr>
 
   -- EXAMPLE 2 --
   <tr  class="bibItemsEntry">
@@ -2613,38 +2628,38 @@
   <td width="40%" ><!-- field C -->&nbsp;BP365 .E8 <!-- field # --><!-- field v -->&nbsp;1970 <!-- field ! --><!-- field y --><a href="/search~S6?/cBP365+.E8/cbp++365+e8/-3,-1,,E/browse"><strong>Show Nearby Items On Shelf</strong></a></td>
   <td width="30%" ><!-- field % -->&nbsp;CHECK SHELVES </td></tr>
 
+  -- EXAMPLE 5 --
+  http://catalog.waukeganpl.org/record=b1292762&searchscope=0
+  <tr class="bibItemsEntry">
+
+  <td width="35%"><!-- field 1 -->&nbsp;Children's Magazine
+  </td>
+  <td width="41%"><!-- field C -->&nbsp;MAGAZINE <!-- field v -->&nbsp;no.26 Nov 2008 <!-- field # -->&nbsp;<a href="/search~S7?/cMAGAZINE/cmagazine/-3,-1,,E/browse"><img border="0" alt="Nearby on shelf" src="/screens/bullet.gif"></a></td>
+  <td width="24%"><!-- field % -->&nbsp;DUE 08-31-09BILLED </td></tr>
+
   */
-  $ok = preg_match_all('/<tr  class="bibItemsEntry">(.*?<\/tr>(?:<tr>.*?<\/tr>|))/si', $fetched_html, $holding_matches, PREG_SET_ORDER);
-  if ($ok) {
+  if (preg_match_all('/<tr +class="bibItemsEntry">(.*?<\/tr>(?:<tr>.*?<\/tr>|))/si', $html, $holding_matches, PREG_SET_ORDER)) {
     foreach ($holding_matches as $holding) {
-      $ok = preg_match_all('/<!-- field (.) -->(?: *&nbsp; *|)(?:<a.*?' . '>|)(.*?)(?:<\/|<!|\n|&nbsp;)/si', $holding[1], $matches, PREG_SET_ORDER);
-
-      /* Fields:
-       * 1,$: Location
-       * !: OpacMSG
-       * %: Item Status
-       * C: Class number
-       * v: class...location?
-       * #: copy #
-       */
-      foreach ($matches as $match) {
-        $name = $code_2_human[$match[1]];
-        $value = trim(decode_entities(str_replace("&nbsp;", " ", strip_tags($match[2]))));
-        $field[$name] = $value;
+      if (preg_match_all('/<!-- field (.) -->(?: *&nbsp; *|)(?:<a.*?' . '>|)(.*?)(?=<\/td|<!--)/si', $holding[1], $matches, PREG_SET_ORDER)) {
+        // Initialize the item.
+        $item = array();
+        // Scan through all <!-- field X -->... matches.
+        foreach ($matches as $match) {
+          $name = $code_2_human[$match[1]];
+          $value = trim(decode_entities(str_replace("&nbsp;", " ", strip_tags($match[2]))));
+          $item[$name] = $value;
+        }
+        // There can also be a URL assigned to the item: look for it.
+        $ok = preg_match('/colspan=".">.*?<a href="(http.*)">([^<]+)</si', $holding[1], $matches);
+        if ($ok) {
+          $item['link']['url'] = $matches[1];
+          $value = trim(decode_entities(str_replace("&nbsp;", " ", strip_tags($matches[2]))));
+          $item['link']['title'] = $value;
+        }
+        $items[] = $item;
       }
-      /* There can also be a URL assigned to the item: look for it */
-      $ok = preg_match('/colspan=".">.*?<a href="(http.*)">([^<]+)</si', $holding[1], $matches);
-      if ($ok) {
-        $field['link']['url'] = $matches[1];
-        $value = trim(decode_entities(str_replace("&nbsp;", " ", strip_tags($matches[2]))));
-        $field['link']['title'] = $value;
-      }
-
-      $items[] = $field;
     }
   }
-  $cache[$cid] = $items;
-  cache_set($cid, $items, 'cache', time()+(24*3600)); // Cache for one day
   return $items;
 }
 
Index: tests/millennium_basic_functions.test
--- tests/millennium_basic_functions.test Base (1.1.2.5)
+++ tests/millennium_basic_functions.test Locally Modified (Based On 1.1.2.5)
@@ -121,6 +121,119 @@
       }
     }
 
+    // Test HTML holdings table -> item parsing
+    $holdings_tests = array(
+      array(
+        '<tr  class="bibItemsEntry">
+        <td width="22%" > <!-- field 1 -->&nbsp; CEM GENERAL
+        </td>
+        <td width="33%" > <!-- field C -->&nbsp;<a href="/search*spi/cQA76.76.P37+M49+2007/cqa+++76.76+p37+m49+2007/-3,-1,,E/browse">QA76.76.P37 M49 2007</a>&nbsp; <!-- field v -->&nbsp;&nbsp; <!-- field # -->&nbsp;</td>
+        <td width="22%" > <!-- field ! --></td>
+        <td width="23%" > <!-- field % -->&nbsp; DISPONIBLE</td></tr>
+        ',
+        array (
+          'location' => 'CEM GENERAL',
+          'classnumber' => 'QA76.76.P37 M49 2007',
+          'classvolume' => '',
+          'copy' => '',
+          'message' => '',
+          'status' => 'DISPONIBLE',
+        )
+      ),
+      array(
+        '
+        -- EXAMPLE 2 --
+        <tr  class="bibItemsEntry">
+
+        <td width="22%" > <!-- field 1 -->&nbsp; <a href="http://biblioteca.itesm.mx/">MTY Biblioteca Digital</a>
+        </td>
+        <td width="33%" > <!-- field C -->&nbsp;<a href="/search*spi/cRC346+.A3+2005b/crc++346+a3+2005+b/-3,-1,,E/browse">RC346 .A3 2005b</a>&nbsp; <!-- field v -->&nbsp;&nbsp; <!-- field # -->&nbsp;</td>
+        <td width="22%" > <!-- field ! --></td>
+        <td width="23%" > <!-- field % -->&nbsp; DISPONIBLE</td></tr><tr><td align="center" colspan="4">
+
+        <a href="http://xxxxxxxxxxxxxxxxxxx/resourceTOC.aspx?resourceID=54">Consultar el servicio a través de la Biblioteca Digital
+        </td></tr>
+        ',
+        array (
+          'location' => 'MTY Biblioteca Digital',
+          'classnumber' => 'RC346 .A3 2005b',
+          'classvolume' => '',
+          'copy' => '',
+          'message' => '',
+          'status' => 'DISPONIBLE',
+          'link' =>
+          array (
+            'url' => 'http://xxxxxxxxxxxxxxxxxxx/resourceTOC.aspx?resourceID=54',
+            'title' => 'Consultar el servicio a través de la Biblioteca Digital',
+          ),
+        )
+      ),
+      array('
+        -- EXAMPLE 3 --
+        <tr  class="bibItemsEntry">
+
+        <td width="28%" > <!-- field 1 -->&nbsp; CCM HEMEROTECA
+        </td>
+
+        <td width="42%" > <!-- field C -->&nbsp;<a href="/search*spi/cF1201+N49/cf++1201+n49/-3,-1,,E/browse">F1201 N49</a>&nbsp; <!-- field v -->15: 1992 Ene.-Mar.&nbsp; <!-- field # -->&nbsp;</td>
+        <td width="30%" > <!-- field % -->&nbsp; DISPONIBLE</td></tr>
+        ',
+        array (
+          'location' => 'CCM HEMEROTECA',
+          'classnumber' => 'F1201 N49',
+          'classvolume' => '15: 1992 Ene.-Mar.',
+          'copy' => '',
+          'status' => 'DISPONIBLE',
+        )
+      ),
+      array(
+        '
+        -- EXAMPLE 4 --
+        <tr  class="bibItemsEntry">
+
+        <td width="30%" ><!-- field $ -->&nbsp;DEN Main
+        </td>
+
+        <td width="40%" ><!-- field C -->&nbsp;BP365 .E8 <!-- field # --><!-- field v -->&nbsp;1970 <!-- field ! --><!-- field y --><a href="/search~S6?/cBP365+.E8/cbp++365+e8/-3,-1,,E/browse"><strong>Show Nearby Items On Shelf</strong></a></td>
+        <td width="30%" ><!-- field % -->&nbsp;CHECK SHELVES </td></tr>
+        ',
+        array (
+          'location' => 'DEN Main',
+          'classnumber' => 'BP365 .E8',
+          'copy' => '',
+          'classvolume' => '1970',
+          'message' => '',
+          '????' => 'Show Nearby Items On Shelf',
+          'status' => 'CHECK SHELVES',
+        )
+      ),
+      array(
+        '
+        -- EXAMPLE 5 --
+        http://catalog.waukeganpl.org/record=b1292762&searchscope=0
+        <tr class="bibItemsEntry">
+
+        <td width="35%"><!-- field 1 -->&nbsp;Childrens Magazine
+        </td>
+        <td width="41%"><!-- field C -->&nbsp;MAGAZINE <!-- field v -->&nbsp;no.26 Nov 2008 <!-- field # -->&nbsp;<a href="/search~S7?/cMAGAZINE/cmagazine/-3,-1,,E/browse"><img border="0" alt="Nearby on shelf" src="/screens/bullet.gif"></a></td>
+        <td width="24%"><!-- field % -->&nbsp;DUE 08-31-09BILLED </td></tr>
+        ',
+        array (
+          'location' => 'Childrens Magazine',
+          'classnumber' => 'MAGAZINE',
+          'classvolume' => 'no.26 Nov 2008',
+          'copy' => '',
+          'status' => 'DUE 08-31-09BILLED',
+        )
+      )
+    );
+    foreach ($holdings_tests as $testnum => $test) {
+      $items = millennium_parse_holdings_from_html($test[0]);
+      $parsed = $items[0];
+      $should_be = $test[1];
+      $this->assertEqual($parsed, $should_be, t("Holdings parser test %testnum"));
+    }
+
     // Test the get_real_baseurl parser
     // Bad URLs
     $bad_urls = explode('|', 'http:/example.com|example.com|ftp://example.com');
