3

I have the following object, here printed as an array. This object is built from a SOAP request.

AdminInfo Object (
  [Supplier] => Supplier Object (
      [Party] => Party Object (
          [OrgInfo] => OrgInfo Object (
              [CompanyName] => Bobs
              [IDInfo] => Array of IDInfo Objects (
                  [0] => IDInfo Object (
                      [IDQualifierCode] => 
                      [IDNum] => 
                    )
                  [1] => IDInfo Object (
                      [IDQualifierCode] => CompanyID
                      [IDNum] => 83e26599-d40g-4cba-9791-7d7c83de282c
                    )
                  [2] => IDInfo Object (
                      [IDQualifierCode] => TID
                      [IDNum] => BOBTID01020304
                    )
                  [3] => IDInfo Object (
                      [IDQualifierCode] => Token
                      [IDNum] => c784570e-044d-42c8-98fe-af9f7c1747f5
                    )
                )
            )
          [ContactInfo] => ContactInfo Object (
              [ContactJobTitle] => 
              [Communications] => Comm Object (
                  [CommQualifier] => 
                  [CommPhone] => 
                  [CommEmail] => 
                  [Address] => Address Object (
                      [Address1] => 
                      [Address2] => 
                      [City] => 
                      [StateProvince] => 
                      [PostalCode] => 
                      [CountryCode] => 
                    )
                )
              [ContactName] => PersonName Object (
                  [FirstName] => 
                  [MiddleName] => 
                  [LastName] => 
                )
            )
        )
    )
  [Company] => Company Object (
      [Party] => Party Object (
          [OrgInfo] => OrgInfo Object (
              [CompanyName] => SF
              [IDInfo] => 
            )
          [ContactInfo] => 
        )
    )
  [Facility] => Facility Object (
      [Party] => Party Object (
          [OrgInfo] => Array of OrgInfo Objects (
            )
          [ContactInfo] => ContactInfo Object (
              [ContactJobTitle] => Owner
              [Communications] => Array of Comm Objects(
                  [0] => Comm Object (
                        [CommQualifier] => WP
                        [CommPhone] => 1234567890
                    )
                  [1] => Comm Object (
                        [CommQualifier] => SA
                        [Address] => Address Object (
                            [Address1] => 123 NE 14th St 
                            [City] => Nowhere
                            [StateProvince] => ND
                            [PostalCode] => 12345
                            [CountryCode] => US
                          )
                      )
                  [2] => 
                  [3] => 
                )
              [ContactName] => PersonName Object (
                  [FirstName] => Bob
                  [MiddleName] => 
                  [LastName] => Tester
                )
            )
        )
    )
)

What I want to do is to remove all the empty elements and be returned with this object

AdminInfo Object (
  [Supplier] => Supplier Object (
      [Party] => Party Object (
          [OrgInfo] => OrgInfo Object (
              [CompanyName] => Bobs
              [IDInfo] => Array of IDInfo Objects (
                  [0] => IDInfo Object (
                      [IDQualifierCode] => 
                      [IDNum] => 
                    )
                  [1] => IDInfo Object (
                      [IDQualifierCode] => CompanyID
                      [IDNum] => 83e26599-d40g-4cba-9791-7d7c83de282c
                    )
                  [2] => IDInfo Object (
                      [IDQualifierCode] => TID
                      [IDNum] => BOBTID01020304
                    )
                  [3] => IDInfo Object (
                      [IDQualifierCode] => Token
                      [IDNum] => c784570e-044d-42c8-98fe-af9f7c1747f5
                    )
                )
            )
        )
    )
  [Company] => Company Object (
      [Party] => Party Object (
          [OrgInfo] => OrgInfo Object (
              [CompanyName] => SF
            )
        )
    )
  [Facility] => Facility Object (
      [Party] => Party Object (
          [ContactInfo] => ContactInfo Object (
              [ContactJobTitle] => Owner
              [Communications] => Array of Comm Objects (
                  [0] => Comm Object (
                        [CommQualifier] => WP
                        [CommPhone] => 1234567890
                    )
                  [1] => Comm Object (
                        [CommQualifier] => SA
                        [Address] => Address Object (
                            [Address1] => 123 NE 14th St 
                            [City] => Nowhere
                            [StateProvince] => ND
                            [PostalCode] => 12345
                            [CountryCode] => US
                          )
                      )
                )
              [ContactName] => PersonName Object (
                  [FirstName] => Bob
                  [LastName] => Tester
                )
            )
        )
    )
)

These attempts don't do it AT ALL; variable $AdminInfo is the Object above...

From solution here: strip null values of json object

$json = json_encode($AdminInfo);
$result = preg_replace('/,\s*"[^"]+":null|"[^"]+":null,?/', '', $json);
$echo $result;

From solution here: How to remove null values from an array?

$json = json_encode($AdminInfo);                // convert to JSON
$arr = (array)json_decode($json);               // convert to an array
$object = (object) array_filter((array) $arr);  // filter the array
$result = json_encode($object);                 // convert it back to JSON
echo $result;

From here: PHP - How to remove empty entries of an array recursively?

function array_remove_empty($haystack)
{
    foreach ($haystack as $key => $value) {
        if (is_array($value)) {
            $haystack[$key] = array_remove_empty($haystack[$key]);
        }

        if (empty($value)) {
            unset($haystack[$key]);
        }
    }

    return $haystack;
}

$json = json_encode($AdminInfo);          // convert to JSON
$arr = (array)json_decode($json);         // convert to an array
print_r(array_remove_empty($arr));        // run through array_remove_empty function and print

From solution here: Remove items from multidimensional array in PHP

function cleanArray($array) {
    if (is_array($array)) {
        foreach ($array as $key => $sub_array)
        {
            $result = cleanArray($sub_array);
            if ($result === false) {
                unset($array[$key]);
            } else {
                $array[$key] = $result;
            }
        }
    }
    if (empty($array)) {
        return false;
    }
    return $array;
}

$json = json_encode($AdminInfo);          // convert to JSON
$arr = (array)json_decode($json);         // convert to an array
print_r(cleanArray($arr));                // run through cleanArray function and print

Edit
AdminInfo object as JSON:

{
    "Supplier":{
        "Party":{
            "OrgInfo":{
                "CompanyName":"Bobs",
                "IDInfo":[
                    {
                        "IDQualifierCode":null,
                        "IDNum":""
                    },
                    {
                        "IDQualifierCode":"CompanyID",
                        "IDNum":"83e26599-d40g-4cba-9791-7d7c83de282c"
                    },
                    {
                        "IDQualifierCode":"TID",
                        "IDNum":"BOBTID01020304"
                    },
                    {
                        "IDQualifierCode":"Token",
                        "IDNum":"c784570e-044d-42c8-98fe-af9f7c1747f5"
                    }
                ]
            },
            "ContactInfo":{
                "ContactJobTitle":"",
                "Communications":{
                    "CommQualifier":null,
                    "CommPhone":"",
                    "CommEmail":"",
                    "Address":{
                        "Address1":"",
                        "Address2":"",
                        "City":"",
                        "StateProvince":null,
                        "PostalCode":"",
                        "CountryCode":null
                    }
                },
                "ContactName":{
                    "FirstName":"",
                    "MiddleName":"",
                    "LastName":""
                }
            }
        }
    },
    "Company":{
        "Party":{
            "OrgInfo":{
                "CompanyName":"SF",
                "IDInfo":null
            },
            "ContactInfo":null
        }
    },
    "Facility":{
        "Party":{
            "OrgInfo":[

            ],
            "ContactInfo":{
                "ContactJobTitle":"",
                "Communications":[
                    {
                        "CommQualifier":null,
                        "CommPhone":"",
                        "CommEmail":"",
                        "Address":{
                            "Address1":"",
                            "Address2":"",
                            "City":"",
                            "StateProvince":null,
                            "PostalCode":"",
                            "CountryCode":null
                        }
                    },
                    null,
                    null,
                    null
                ],
                "ContactName":{
                    "FirstName":"Bob",
                    "MiddleName":"",
                    "LastName":"Tester"
                }
            }
        }
    }
}
MB34
  • 4,210
  • 12
  • 59
  • 110
  • Can you provide a usable/testable object instead of just the dumped version? – Patrick Q May 04 '18 at 17:30
  • in JSON or what format??? – MB34 May 04 '18 at 17:33
  • Anything that we can simply copy/paste to run the above attempts and try to resolve, instead of spending the time manually re-creating your object. – Patrick Q May 04 '18 at 17:36
  • You COULD convert the object into an array and loop over it and unset all variables that are don't have a variable in it. Use recursion to loop trough every object. – Joas May 04 '18 at 17:42
  • @Joas, that is what two of the solutions tried does and they did not work. – MB34 May 04 '18 at 18:41
  • @PatrickQ Just added the object as JSON – MB34 May 04 '18 at 18:43
  • Also, the Facility object in your JSON doesn't match the Facility object in the SOAP output – Nick May 06 '18 at 00:10
  • Why don't you want (for example) `$AdminInfo->Supplier->Party->OrgInfo->IDInfo[0]` removed? It is empty too... – Nick May 06 '18 at 00:25

4 Answers4

1

After a little bit of headscratching I came up with a recursive function that, like I suggested earlier, converts the object into an array to check if the variables are set to null.

If all variables inside that object are null, the parent is indexed to set the reference of the object to null.

I tried to explain and document the code as best as I can.

Please don't just copy the code and be done with it but read it trough and try to learn from the code I supplied.

/**
    Unsets all empty variables in $object
*/
function loopTrough(&$object, &$parent = null, $key = null, $objectIsArray = false, $parentIsArray = false)
{
    // Keep track of amount of vars and amount of null vars
    $vars = 0;
    $null = 0;
    foreach($object as $index => $value)
    {
        $vars = $vars + 1;

        // Also check if is array
        $isArray = is_array($value);

        // Check if is object
        if (is_object($value) || $isArray) // using value here is save
        {
            // Loop trough the new object (or array) we found
            if ($objectIsArray)
            {
                loopTrough($object[$index], $object, $index, $isArray, $objectIsArray);
            }
            else
            {
                loopTrough($object->{$index}, $object, $index, $isArray, $objectIsArray);
            }
        }

        // Check if is null
        if ($objectIsArray)
        {
            if (!isset($object[$index]) || $object[$index] == ""){
                $null = $null + 1;
                // We don't want to show null
                unset($object[$index]);
            }
        }
        else
        {
            if (!isset($object->{$index}) || $object->{$index} == "") // use $object->{index} here, and not $value because $value does not change when object reference is changed
            {
                $null = $null + 1;
                // We don't want to show null
                unset($object->{$index});
            }
        }
    }

    // If there are as much null variables as variables
    if ($vars == $null && $parent !== null && $key !== null)
    {
        // Set the parent reference to null
        if ($parentIsArray) // Example exludes arrays, uncomment this if you want values in arrays to be recurisvely set to null
        {
            // unset($parent[$key]);
        }
        else
        {
            unset($parent->{$key});
        }   
    }
}



class Test
{
    public $one;

    public $two;
}

$test = new Test();

$test->one = new Test();
$test->one->two = "On";
$test->two = new Test();
$test->two->one = new Test(); 

var_dump($test);

loopTrough($test);

var_dump($test);
Joas
  • 1,796
  • 1
  • 12
  • 25
  • Still didn't work, Use my object posted as JSON above. – MB34 May 04 '18 at 19:51
  • @MB34 I've eddited the code to support arrays. It makes the code more messy, but it works. – Joas May 04 '18 at 20:55
  • Well, even running it through that code did not remove all the null objects. Apparently, it only sets the value to null. – MB34 May 04 '18 at 21:59
  • @MB34 The code now gives an exact replica of the example provided, except for an inconstancy in your example. You can alter the code yourself further to your needs if some things aren't exactly like you want. – Joas May 05 '18 at 09:57
1

Requirements: Recursively scan nested arrays pruning out empty branches / items.

This is another 'tree walk'.

The only 'tricky' part is letting the processing higher up the tree know whether to add the current item into the output tree or not.

The function that processes a node will return an array that has a 'keep value' flag as well as the value to keep.

JSON Converted to array: Full Working code at eval.in

Output preserves original JSON Data Type: Full Working code at eval.in

Code:

function processList(array $list)
{
    $listResult = ['keepValue' => false, // once set true will propagate upward
                    'value'       => []];

    foreach ($list as $name => $item ) {
        if (is_null($item)) { // see is_scalar test
            continue;
        }

        if (is_scalar($item)) { // keep the value?
            if (!empty($item) || strlen(trim($item)) > 0) {
                $listResult['keepValue'] = true;
                $listResult['value'][$name] = $item;
            }

        } else { // new list... recurse

            $itemResult = processList($item);
            if ($itemResult['keepValue']) {
                $listResult['keepValue'] = true;
                $listResult['value'][$name] = $itemResult['value'];
            }
        }
    }   
    return $listResult;
}    

Run the function:

$source = json_decode($json, true);
$result = processList($source);
print_r($result['value']);

Output:

Array
(
    [Supplier] => Array
        (
            [Party] => Array
                (
                    [OrgInfo] => Array
                        (
                            [CompanyName] => Bobs
                            [IDInfo] => Array
                                (
                                    [1] => Array
                                        (
                                            [IDQualifierCode] => CompanyID
                                            [IDNum] => 83e26599-d40g-4cba-9791-7d7c83de282c
                                        )
                                    [2] => Array
                                        (
                                            [IDQualifierCode] => TID
                                            [IDNum] => BOBTID01020304
                                        )
                                    [3] => Array
                                        (
                                            [IDQualifierCode] => Token
                                            [IDNum] => c784570e-044d-42c8-98fe-af9f7c1747f5
                                        )
                                )
                        )
                )
        )
    [Company] => Array
        (
            [Party] => Array
                (
                    [OrgInfo] => Array
                        (
                            [CompanyName] => SF
                        )
                )
        )
    [Facility] => Array
        (
            [Party] => Array
                (
                    [ContactInfo] => Array
                        (
                            [ContactName] => Array
                                (
                                    [FirstName] => Bob
                                    [LastName] => Tester
                                )
                        )
                )
        )
)
Ryan Vincent
  • 4,483
  • 7
  • 22
  • 31
  • warning, 1 problem with empty() is that it removes the string literal "0" and the number 0. `if(empty($v) && $v!=="0" && $v!==0){}` – hanshenrik May 06 '18 at 11:02
0

Like I suggested earlier you COULD convert the object into an array and recursively loop trough the elements to check if they are null.

The recursive function is going to be quite complicated since you don't just want to remove null variables, but remove everything that contains null only variables.

Heres an example without the recursion which just removes null variables from an object:

class A
{
    public $var = "aVar";
    public $var1 = null;
}

$a = new A();

var_dump($a);

$array = (array)$a;

foreach($array as $key => $value)
{
    if (is_null($value)){
        unset($array[$key]);
    }
}

var_dump($array);
Joas
  • 1,796
  • 1
  • 12
  • 25
  • "Heres an example without the recursion" This is an example, without the recursion. If you want it to work on a multi dimensional array, you'll need to program in the recursion. @MB34 – Joas May 04 '18 at 19:29
  • As I said earlier, I've already tried something like this in my attempts. – MB34 May 04 '18 at 19:33
0

seriously don't got time to test it, but edit: tested it, had a bug in the original code (had clean_iterable(NULL,$v); instead of clean_iterable(NULL,$v[$key]);, fixed it, this seem to work:

function clean_iterable(Iterable $v=NULL,Iterable &$vv=NULL):Iterable{
    if(isset($vv)){
        $v=&$vv;
    }
    if(empty($v)){
        return $v;
    }
    foreach($v as $key=>$val){
        if(empty($val)){
            unset($v[$key]);
        }elseif(is_iterable($val)){
            clean_iterable(NULL,$v[$key]);
        }
    }
    return $v;
}
hanshenrik
  • 19,904
  • 4
  • 43
  • 89