最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Including the rendering of an HTML document into another HTML document - Stack Overflow

programmeradmin5浏览0评论

I have a string representing a stand-alone (and valid XHTML 1.0 Strict) HTML document, something like

var html = "<?xml ... <!DOCTYPE ... <html><head><style>...</style></head>
                  <body><table>...</table></body></html>";

The body of this HTML document contains a table whose CSS-style is described in the head of the HTML document.

I also have a DOM-tree of another HTML document. How can I include into this DOM-tree the DOM-tree of the table with the correct style (as described in the HTML-string)?

I am especially interested in a jQuery-based solution.

EDIT: To be more concrete, an example of an HTML-string that I'm talking about is embedded into this XML-document.

I have a string representing a stand-alone (and valid XHTML 1.0 Strict) HTML document, something like

var html = "<?xml ... <!DOCTYPE ... <html><head><style>...</style></head>
                  <body><table>...</table></body></html>";

The body of this HTML document contains a table whose CSS-style is described in the head of the HTML document.

I also have a DOM-tree of another HTML document. How can I include into this DOM-tree the DOM-tree of the table with the correct style (as described in the HTML-string)?

I am especially interested in a jQuery-based solution.

EDIT: To be more concrete, an example of an HTML-string that I'm talking about is embedded into this XML-document.

Share Improve this question edited Apr 20, 2009 at 19:23 Kaarel asked Apr 15, 2009 at 17:03 KaarelKaarel 10.7k4 gold badges58 silver badges80 bronze badges
Add a comment  | 

6 Answers 6

Reset to default 17 +50

I may be waaaay missing the point, but why not load the string into an IFRAME to render - this solves all the problems of having two separate DOM trees, and two separate sets of CSS rules, to me.

This code will do it:

$(function() {
        var $frame = $('<iframe style="width:200px; height:100px; border: 0px;">');
        $('body').html( $frame );
        setTimeout( function() {
                var doc = $frame[0].contentWindow.document;
                var $body = $('body',doc);
                $body.html(your_html);
        }, 1 );
});

(which I lifted from here: putting html inside an iframe (using javascript))

Then if you are concerned about the size of the IFRAME, you can set it with:

$frame[0].style.height = $frame[0].contentWindow.document.body.offsetHeight + 'px';
$frame[0].style.width = $frame[0].contentWindow.document.body.offsetWidth + 'px';

There's no sense in having two full DOM trees on the same page, so you'll want to extract out what you want and only use that.

Convert the string to a jQuery object and parse out what you need like this:

var html = "<html><head><style>...</style></head>
            <body><table>...</table></body></html>";

// Not sure if you are a trying to merge to DOMs together or just
// trying to place what you want on the page so, I'm going to go
// with the former as it may be more tricky.
var other_html = "<html><head><style>...</style></head>
                   <body><!-- some stuff --></body></html>";

var jq_html = $(html);
var jq_other_html = $(other_html);

var style = jq_html.find('head').find('style');
var table_and_stuff = jq_html.find('body').html();

jq_other_html.find('head').append(style).end().append(table_and_stuff);

That should probably do it. The CSS should automatically be recognized by the browser once it's inserted into the page.

NOTE:
For the new CSS style sheet to only add new styles and not override your current one(s), you must prepend the sheet to the head tag and not append it. So, the last line would need to be like this instead:

jq_other_html.find('head').prepend(style).end().append(table_and_stuff);

Instead of improving my other answer, I'd rather make a new one since I basically need to re-write it to work with how you want it and the old answer may help people for other reasons...

So, after extracting out the HTML-string from the XML you link to, you can go forth with it like this:

// First we'll extract out the parts of the HTML-string that we need.
var jq_html = $(html_from_xml);
var style = jq_html.find('head').find('style').html();
var style_string = style.toString();
var table_and_stuff = jq_html.find('body').html();

// If you want to place it into the existing page's DOM,
// we need to place it inside a new DIV with a known ID...
$('body').append('<div id="new_stuff"></div>');
$('#new_stuff').html(table_and_stuff);

// Now, we need to re-write the styles so that they only
// affect the content of the 'new_stuff' DIV:
styles_array = style_string.split('}');
var new_styles = '';
$.each(styles_array,function(i) { 
    if(i<(styles_array.length-1)) { 
        new_styles += "#new_stuff "+styles_array[i]+"}"; 
    }
})
$('head').append('<style type="text/css">'+new_styles+'</style>');

And that should really do it. The trick is that CSS will choose the most specific style for the case. So, if you have a <td> inside the "newstuff" div, it will get the style from the new stylesheet. If you have a <td> outside of that "newstuff" div, it will get the old style.

I hope this solves your problem.

Insert it into an inline frame.

Using a question I asked earlier, I have a solution like this:

First, have an iframe, with some id

<iframe id="preview" src="/empty.html"></iframe>

Then style it:

iframe#preview
{
    margin: 30px 10px;
    width: 90%;
    height: 800px;
}

And here's a function to insert an html text into that frame (uses jquery)

function preview( html )
{
    var doc = $("#preview")[0].contentWindow.document
    var body = $('body',doc)
    body.html( html );    
}

I used this to successfully render the content of the html, including whatever embedded css it might include.

Here is my code that does what you described. Two things to note

  1. For some reason find() did not work on the 'on-the-fly' dom that I got from jquery object, may be someone can find out what am I doing wrong there
  2. I have appended this new dom to 'body' element for illustration purposes. You could just as easily append it to your second dom

   var insertStr = "your string here";

   var newDom = $(insertStr); // getting [meta style table.drs]

   // I had to use the array as newDom.find would not work for me which I was expecting would work
   var styleText = $(newDom[1]).text();
   var tableElm = $(newDom[2]);
   $(newDom[2]).appendTo('body');

   var selectors = styleText.split(/{[\s\w\.\(\)':;"#%=/-]*}/);

   var styles = styleText.match(/{[\s\w\.\(\)':;"#%=/-]*}/g);



   for ( var i =0; i < styles.length; i++ ) {
       var style = styles[i];

       style = style.replace("{","");

   style = style.replace("}","");

   if ( selectors[i].indexOf("table.drs") > -1 ) { // identify top-level elm
       // apply to self
       tableElm.attr('style',style);

   } else {

       // apply to its children
       tableElm.find(selectors[i]).attr('style',style);

   }

}

Here's some test code demonstrating how I'd do this. The code extracts the <style> element from the passed HTML and adds a custom ID to all the selectors, then injects the HTML into a <div> with that ID. That way all the CSS passed by the HTML will only apply to the injected table:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    var html = '<?xml version="1.0" encoding="UTF-8"?>\n\
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n\
    <html xmlns="http://www.w3.org/1999/xhtml">\n\
    <head>\n\
    <title></title>\n\
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n\
    <style type="text/css">\n\
    div.dom { background-color: #ace; margin-bottom: 0.5em } table.drs { font-family: monospace; padding: 0.4em 0.4em 0.4em 0.4em; border: 1px solid black; margin-bottom: 2em; background-color: #eee; border-collapse: collapse }\n\
    td { vertical-align: top; padding: 0.3em 0.3em 0.3em 0.3em; border: 1px solid black }\n\
    td.op { vertical-align: middle; font-size: 110%; border: none }\n\
    </style>\n\
    </head>\n\
    <body><table class="drs"><tr><td><div class="dom">[]</div></td></tr></table></body>\n\
    </html>';

    var style = html.match(/<style([^>]*)>([^<]*)<\/style>/);
    var modifiedStyle = style[2].replace(/\s*(} |^|\n)\s*([^{]+)/g, " $1 #inserthere $2");

    $(document).find('head').prepend("<style" + style[1] + ">" + modifiedStyle + "</style");
    $("#inserthere").append($(html).children());
    });
</script>
</head>
<body>
<div id="inserthere">
</div>
</body>
</html>

Obviously you will have to modify this for your situation, but it's a starting point.

发布评论

评论列表(0)

  1. 暂无评论