The root of the problem seems to be a static private field in the TreeView control called "populateNodeScript" which contains the hard-coded (!) <script> tag - my solution uses reflection to fix this string so that when the TreeView uses this value it uses the fixed value rather than th default.
This is the code that needs to be placed in the OnInit handler of your page (I use OnInit but anywhere before OnPreRender should do the trick):
private static void FixTreeViewScriptNode()
{
FieldInfo field = typeof(TreeView).GetField("populateNodeScript",
BindingFlags.NonPublic | BindingFlags.Static);
string populateNodeScript = Convert.ToString(field.GetValue(null));
field.SetValue(null, populateNodeScript.Replace("<script>", "<script type="\">"));
}
Note: I'm not sure of the performance impact of this script as I havent had much of a chance to performance test it yet - I expect the reflection penalty will have less of a hit (memory-wise anyway) than the render-to-string HttpHandler method I have detailed before. There is always scope for improvement - as we're setting a static field then we should only need to set this once, though I'm unsure when or where (global.asax?)