How do I pull out only the content within the body tag of an ajax response that contains an entire HTML page?
I have the following code:
$.ajax(
{
url: rootPath + "Framework/GetPartial",
data: { partialName: partialName },
type: "POST",
success: function (response)
{
$('#loading').hide();
$('#partialContent').hide().html(response).fadeIn();
},
error: function (xhr, textStatus, errorThrown)
{
$('#loading').hide();
$('#partialContent').hide().html('An error occurred. Details below:<br /><br />' + xhr.responseText).fadeIn();
}
});
What I am concerned with is the error handling function. When an error occurs on the server an html page is sent as the response containing detailed debug information. I would like to load this html response into the existing page, but the inclusion of the <HTML>
, <HEAD>
, and <BODY>
tags in the response ruins the formatting of the entire page. How would I parse out just the content in the body tag using JQuery in the following HTML response?
<html>
<head>
<title>The method or operation is not implemented.</title>
<style>
body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}
p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
pre {font-family:"Lucida Console";font-size: .9em}
.marker {font-weight: bold; color: black;text-decoration: none;}
.version {color: gray;}
.error {margin-bottom: 10px;}
.expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
</style>
</head>
<body bgcolor="white">
<span><H1>Server Error in '/AlexAndNikki' Application.<hr width=100% size=1 color=silver></H1>
<h2> <i>The method or operation is not implemented.</i> </h2></span>
<font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">
<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
<br><br>
<b> Exception Details: </b>System.NotImplementedException: The method or operation is not implemented.<br><br>
<b>Source Error:</b> <br><br>
<table width=100% bgcolor="#ffffcc">
<tr>
<td>
<code><pre>
Line 19: public PartialViewResult GetPartial(string partialName)
Line 20: {
<font color=red>Line 21: throw new NotImplementedException();
</font>Line 22: //System.Threading.Thread.Sleep(3000);
Line 23: if (!ViewExists(partialName))</pre></code>
</td>
</tr>
</table>
<br>
<b> Source File: </b> C:\Users\alex.ford\Documents\Visual Studio 2010\Projects\AlexAndNikki\AlexAndNikki\Controllers\FrameworkController.cs<b> Line: </b> 21
<br><br>
<b>Stack Trace:</b> <br><br>
<table width=100% bgcolor="#ffffcc">
<tr>
<td>
<code><pre>
[NotImplementedException: The method or operation is not implemented.]
AlexAndNikki.Controllers.FrameworkController.GetPartial(String partialName) in C:\Users\alex.ford\Documents\Visual Studio 2010\Projects\AlexAndNikki\AlexAndNikki\Controllers\FrameworkController.cs:21
lambda_method(Closure , ControllerBase , Object[] ) +127
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +258
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +125
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +640
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +312
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +709
System.Web.Mvc.Controller.ExecuteCore() +162
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +58
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +453
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +371
</pre></code>
</td>
</tr>
</table>
<br>
<hr width=100% size=1 color=silver>
<b>Version Information:</b> Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1
</font>
</body>
</html>
<!--
[NotImplementedException]: The method or operation is not implemented.
at AlexAndNikki.Controllers.FrameworkController.GetPartial(String partialName) in C:\Users\alex.ford\Documents\Visual Studio 2010\Projects\AlexAndNikki\AlexAndNikki\Controllers\FrameworkController.cs:line 21
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a()
at Sy开发者_运维百科stem.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.<BeginProcessRequest>b__4()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
-->
EDIT:
Would there be a way to load the response string into an iframe? This would be wonderful if it was possible.
Something like:
$('#partialContent').html('<iframe>' + xhr.responseText + '</iframe>');
Obviously I tried this code and it didn't work, but maybe someone knows how to make an iframe solve the problem?
You can do it like this:
$('#partialContent').hide().html($('body',response).contents()).fadeIn();
This is a shortcut for .empty().append()
underneath, but the main portion is $('body',response)
, which is looking for a <body>
element in the response, then taking it's contents as the elements to append.
I solved my own question.......again. This is only my second question and both times I just spent hours googling and came up with the answer on my own. Sorry guys! I really wanted to accept someone's answer.
Anyway, the easiest solution I found was to load the response string containing the html into an iframe dynamically. Here is an example:
error: function (xhr, textStatus, errorThrown)
{
$('#loading').hide();
$('#partialContent').html('<iframe style="width: 100%; height: 500px; border: solid 1px #000000;" id="errorFrame"></iframe>');
var myFrame = $('#errorFrame')[0]; //top.frames['errorFrame'];
myFrame = myFrame.contentWindow || myFrame.contentDocument.document || myFrame.contentDocument;
myFrame.document.open();
myFrame.document.write(xhr.responseText);
myFrame.document.close();
}
If you have a need for this solution just remember that you have to account for good ol' IE and its failure to follow W3C standards. contentWindow is IE's equivalent to contentDocument. As long as you include myFrame = myFrame.contentWindow || myFrame.contentDocument.document || myFrame.contentDocument;
you'll be fine.
Here is a sample of the error page loaded into an iframe: http://67.2.141.90/AlexAndNikki/Framework/GenerateError
Thanks for all the help everyone!
var content = $('body').html(); //gives you the content of the body
Browsers deal with full HTML pages differently. You should really only return the content you want.
If that's not a possibility, this will look for the <body>
at different levels, depending on which tags the browser has stripped away.
var $response = $( response );
var $content = (( $response.children('body').length ) ? $response.children('body').contents() :
( $response.filter('body').length ) ? $response.filter('body').contents() :
$response).not('style,title,script');
$('#partialContent').hide().html( $content ).fadeIn();
No guarantees, but it may help a bit.
EDIT: Didn't notice you're dealing with the error callback, and trying to concatenate the HTML. My answer above will result in [object Object]
for the concatenation.
Use the code above, except use this when adding the response to the partialContent
.
var $response = $( response );
var $content = (( $response.children('body').length ) ? $response.children('body').contents() :
( $response.filter('body').length ) ? $response.filter('body').contents() :
$response).not('style,title,script');
$('#partialContent').hide().html('An error occurred. Details below:<br /><br />' +
$('<div>').append( $content ).html()).fadeIn();
EDIT: Added code to strip out <title>
, <style>
and <script>
tags since some browsers also give you the content of the <head>
.
精彩评论