2

Below is a sample of the structure of the array. I need to be able to pull out specific values such as : [245][subfields][a]. There are a variable number of [fields] and a variable number of [subfields] inside each of the array. Thanks for any suggestions!

Edit: I have included the array in its navtive JSON format that I am retrieving. I was then using json_decode to convert this into a usable array in php. If you have a better suggestion, please let me know.

Link to pretty array

{"leader":"01220nam  2200265   4500","fields":[{"001":"ocm00000197"},{"005":"19880526181046.0"},{"008":"690325r19681924nyua          00000 eng  "},{"010":{"ind1":" ","ind2":" ","subfields":[{"a":"67-020193 \/\/r832"}]}},{"035":{"ind1":" ","ind2":" ","subfields":[{"a":".b10000021"},{"b":"a    "},{"c":"-"}]}},{"041":{"ind1":"1","ind2":" ","subfields":[{"a":"eng"},{"a":"fre"}]}},{"049":{"ind1":" ","ind2":" ","subfields":[{"a":"JBLA"},{"c":"$8.00"}]}},{"100":{"ind1":"1","ind2":"0","subfields":[{"a":"Allemagne, Henry Ren\u00e2e d',"},{"d":"1863-1950."}]}},{"245":{"ind1":"1","ind2":"0","subfields":[{"a":"Decorative antique ironwork :"},{"b":"a pictorial treasury \/"},{"c":"by Henry Ren\u00e2e d'Allemagne ; introd., bibliography, and translation of captions by Vera K. Ostoia."}]}},{"260":{"ind1":"0","ind2":" ","subfields":[{"a":"New York :"},{"b":"Dover Publications,"},{"c":"[1968]"}]}},{"300":{"ind1":" ","ind2":" ","subfields":[{"a":"x, 415 p. :"},{"b":"(chiefly ill.) ;"},{"c":"31 cm."}]}},{"500":{"ind1":" ","ind2":" ","subfields":[{"a":"\"This Dover edition ... is a republication of all the plates in the two portfolios of Mus\u00e2ee Le Secq des Tournelles \u00e1a Rouen: Ferronnerie ancienne, originally published ... in 1924.\""}]}},{"500":{"ind1":" ","ind2":" ","subfields":[{"a":"\"Other books by Henry Ren\u00e2e d'Allemagne\": p. x."}]}},{"590":{"ind1":" ","ind2":" ","subfields":[{"a":"1373336."}]}},{"650":{"ind1":" ","ind2":"0","subfields":[{"a":"Art metal-work."}]}},{"700":{"ind1":"1","ind2":"0","subfields":[{"a":"Ostoia, Vera K."}]}},{"710":{"ind1":"2","ind2":"0","subfields":[{"a":"Mus\u00e2ee Le Secq des Tournelles."}]}},{"830":{"ind1":" ","ind2":"0","subfields":[{"a":"Dover pictorial archive series."}]}},{"999":{"ind1":" ","ind2":" ","subfields":[{"b":"1"},{"c":"901102"},{"d":"m"},{"e":"b"},{"f":"-"},{"g":"0"}]}},{"945":{"ind1":" ","ind2":" ","subfields":[{"a":"739.4\/ALLEMAGNE,H"},{"g":"1"},{"i":"31184001373336"},{"l":"abx7 "},{"n":"moved from RESEARCH collection - Feb 2012"},{"o":"-"},{"p":"$8.00"},{"s":"-"},{"t":"235"},{"u":"10"},{"v":"0"},{"w":"0"},{"x":"1"},{"y":".i10000021"},{"z":"901102"}]}}]}
rtd1123
  • 482
  • 2
  • 7
  • 3
    That awkward moment when you say "TL;DR" after having read *the title only...* –  Dec 11 '12 at 21:09
  • 1
    If you post an example of the PHP array itself (not the print_r output), I can test if my method below actually does what it's supposed to. – Michael Berkowski Dec 11 '12 at 21:13
  • Maybe this could be useful > http://stackoverflow.com/questions/1019076/how-to-search-by-key-value-in-a-multidimensional-array-in-php – emco Dec 11 '12 at 21:32
  • Michael, Yes, it is a MARC record. The worst format known to man kind! I have added the JSON string that I am retrieving, then using json_decode to create the array in PHP. I also threw in a link to the array as a print_r so anyone can see the structure in a more easy to read fashion. – rtd1123 Dec 12 '12 at 04:10
  • I can't believe some people closed my question when there was obviously a solution to it proposed by some brilliant minds. Just because you don't understand the topic of discussion, doesn't mean that it's "not a real question". – rtd1123 Dec 12 '12 at 15:02

4 Answers4

1

So it looks like you'll need a method to loop over the fields key to check the first key of each of its sub-arrays to match your searched item.

// Loop over the fields, which are each arrays numerically indexed...
foreach ($record['fields'] as $key => $field) {
  // Get the field's first array key, which is 010, 015, etc...
  $marc_keys = array_keys($field);
  // the first key...
  $marc_field = $marc_keys[0];
  // Note in PHP 5.4 you could dereference it more easily like
  // $marc_field = array_keys($field)[0];

  // Test if the key you found is the one you want...
  if ($marc_field == '245') {
     foreach ($field[$marc_field]['subfields'] as $subkey => $subfield) {
       // Get the subfield identifier (the first array key)
       $sf_keys = array_keys($subfield);
       $sf_identifier = $sf_keys[0];
       if ($sf_identifier == 'a') {
          // Congratulations Arthur, you found the grail....
          // Do something with it...
       } 
     }
  }
  // Otherwise, keep looping until you find the one you need...
}

As a function:

You are best served to convert this to a function that accepts the $field,$subfield as parameters:

Updated to account for multiple subfields of the same type, and return an array:

function getSubfield($record, $in_field, $in_subfield) {
    // Array to hold output for multiple like subfields
    $subfields_returned = array();

    foreach ($record['fields'] as $key => $field) {
      $marc_keys = array_keys($field);
      $marc_field = $marc_keys[0];

      // Test if the key you found is the one you want (which is the $in_field param)
      if ($marc_field == $in_field) {
         foreach ($field[$marc_field]['subfields'] as $subkey => $subfield) {

           $sf_keys = array_keys($subfield);
           $sf_identifier = $sf_keys[0];

           // And match the subfield to the function param $in_subfield

           if ($sf_identifier == $in_subfield) {
              // Congratulations Arthur, you found the grail....
              // Return it...
              $subfields_returned[] = $subfield[$sf_identifier];
           }
         }
          // After the subfield loop, you can return the accumulated array
         if (count($subfields_returned) > 0) return $subfields_returned;
      }
      // Otherwise, keep looping until you find the one you need...
    }
}

Here is a demonstration

...With a record I cobbled together partially...

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
  • Michael, this was very similar to an idea that I first started with, but the speed wasn't adequately fast for the application it's being used in. It may do the trick, but perhaps I need to consider some speed enhancements. – rtd1123 Dec 12 '12 at 04:16
  • Hi Michael, I just completed a test on your proposed solution and it works great. The only caveat was with those fields that had multiple subfields. Like the Field 041 Subfield "a" could have two entries for subfield "a". For all other single entry tests, it works fantastic and I want to thank you so much for the hard work that you obviously put into this! – rtd1123 Dec 12 '12 at 14:58
  • 1
    @RichieD You're welcome - I have a soft spot for library stuff. MARC may be the worst format known to man, but how many other formats are still used globally after 45 years? – Michael Berkowski Dec 12 '12 at 15:01
  • 1
    @RichieD For multiple subfields, you can accumulate them into an array instead of returning. It means you have to loop through all of them though and can't bail out early. I'll update my example. – Michael Berkowski Dec 12 '12 at 15:02
  • 1
    Here's the updated example.. I'll paste the new code above. – Michael Berkowski Dec 12 '12 at 15:05
  • Michael, thank you so much for the hard work. I have updated to give you the accepted answer as it works just as easily as the other solution but in seemingly less time from the few tests that I have run. – rtd1123 Dec 12 '12 at 15:19
  • You're right about the MARC format, it definitely has withstood the test of time. I just wish there was a fast/simple way to switch between MARC and a normalized format that could be usable in a database like MySQL. – rtd1123 Dec 12 '12 at 15:20
1
// behaves like  array(*, 245, *, 'subfields', *, 'a', *);
// where * is a wildcard for 0 or more keys
$keySequence = array(245, 'subfields', 'a');


$arr = array();
$arr[245]['subfields']['a'] = 'i match';
$arr[245]['subfields'][7]['a'] = 'i match';
$arr[0][0][0][245][0][0]['subfields']['subfields'][0]['a']['a'] = 'i match';
$arr[0][0][0][0][0][0]['subfields']['subfields'][0]['a']['a'] = 'i dont match';
$arr[0][0][0][0][0][0]['subfields']['subfields'][0]['a']['a'] = 'i dont match';





$iter = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
$filtered = new CallbackFilterIterator($iter, function ($_, $_, $iterator) use ($keySequence) {
    $i = 0;
    $max = count($keySequence);
    foreach (range(0, $iterator->getDepth()) as $depth) {
        if ($keySequence[$i] === $iterator->getSubIterator($depth)->key())
            $i++;
        if ($i === $max)
            return true;
    }
    return $i === $max;
});

foreach ($filtered as $leafVal) {
    echo "$leafVal\n";
}

http://codepad.viper-7.com/9t4qVO

goat
  • 31,486
  • 7
  • 73
  • 96
  • This might be exactly what I was looking for, but I will test it in the morning to be sure. – rtd1123 Dec 12 '12 at 04:14
  • I just finished a test of this and it does return exactly what I need. I should point out that it does require PHP 5.4 or above, otherwise you have to add a class for "CallbackFilterIterator". Other than that, it was very simply to implement. Thank you for your hard work on this! – rtd1123 Dec 12 '12 at 15:00
0

If you're going to be doing a lot of custom searches on this data, you could consider converting the array to XML, using any of a variety of already written functions. Then you can use XPath to query the data flexibly.

DWright
  • 9,258
  • 4
  • 36
  • 53
  • Speed is a primary concern of mine, so I don't know of the speed implications of converting this to XML. If you still think this is the best route, it's definitely worth a shot. – rtd1123 Dec 12 '12 at 04:12
  • Richie, if speed is important, it's best to keep the data in its original array form. – DWright Dec 12 '12 at 15:39
  • Well, I would agree with that, but I need to parse this data to be displayed on each page of the site, as it is called from the database. Also, I am creating search indexes from this data using Apache Solr, which is why I needed to extract particular elements. – rtd1123 Dec 12 '12 at 16:29
0
function recursiveArrayIterator($arr){
    foreach($arr as $key => $arr2){
        if(is_array($arr2)){
           recursiveArrayIterator($arr2);
        }
    }
}
$arr = array(array('key'=>'value'));
recursiveArrayIterator($arr);

i don't your requirement but this may help you.

web2students.com
  • 307
  • 2
  • 16
  • I was looking at this before, but all I could get it to do was print out all the elements of the array. I wasn't finding an easy method to retrieve a particular part of the array. Possibly because this class is lacking a lot of documentation and I've never used it before. – rtd1123 Dec 12 '12 at 04:11