If you are using PHP 5.2+ you’re best bet is to just make a PHP array or object and use json_encode().
UPDATED:
$cats = get_categories();
$output = array('categories' => array());
foreach ($cats as $cat) {
$cat_output = array(
'cat_id' => $cat->term_id,
'cat_name' => $cat->name,
'posts' => array(),
);
// should be able to use -1 to get all posts, rather than 9999
$args = array('numberposts=" => -1, "category' => $cat->cat_ID);
$myposts = get_posts($args);
foreach( $myposts as $post ) {
if ($youtube_id = get_post_meta($post->ID, 'apls_video_youtube', TRUE)) {
$url = "http://www.youtube.com/watch?v={$youtube_id}";
} else {
$url = get_post_meta($post->ID, 'apls_video_hosted', TRUE);
}
$cat_output['posts'][] = array(
'name' => get_the_title($post->ID),
'url' => $url,
);
}
$output['categories'][] = $cat_output;
}
header("Content-type: application/json");
die(json_encode($output));