protected function equals($old, $new)
    {
        if (is_array($old)) {
            // compare arrays
            if (array_keys($old) != array_keys($new)) {
                return false;
            }

            foreach (array_keys($old) as $key) {
                if ( ! $this->equals($old[$key], $new[$key])) {
                    return false;
                }
            }

            return true;
        }

        if ( ! is_object($old) ) {
            // compare non-array scalars
            return ($old == $new);
        }

        if (get_class($old) != get_class($new)) {
            // compare object by class name
            return false;
        }

        // compare each sub-node
        foreach ($old->getSubNodeNames() as $property) {
            if ( ! $this->equals($old->$property, $new->$property)) {
                return false;
            }
        }

        return true;
    }