Puedo cargar un documento HTML completo en un fragmento de documento en Internet Explorer?

Aquí algo que he estado teniendo un poco de dificultad con. Tengo un local de secuencia de comandos de cliente que necesita para permitir que un usuario capturar una página web remota y de búsqueda que la página resultante para los formularios. Con el fin de hacer esto (sin regex), es necesario analizar el documento en un totalmente transitable objeto DOM.

Algunas limitaciones que me gustaría subrayar:

  • No quiero usar librerías como jQuery). Hay demasiado infladas por lo que tengo que hacer aquí.
  • Bajo ninguna circunstancia se debe a que las secuencias de comandos remoto página de ser ejecutado (por razones de seguridad).
  • DOM Api, tales como getElementsByTagName, deben estar disponibles.
  • Sólo se necesita para trabajar en Internet Explorer, pero en el 7 por lo menos.
  • Vamos a pretender que no tienen acceso a un servidor. Lo hago, pero no los puedo usar para esto.

Lo he intentado

Suponiendo que tengo un completo documento HTML de la cadena (incluyendo la declaración DOCTYPE) en la variable html, he aquí lo que yo he probado hasta ahora:

var frag = document.createDocumentFragment(),
div  = frag.appendChild(document.createElement("div"));

div.outerHTML = html;
//-> results in an empty fragment

div.insertAdjacentHTML("afterEnd", html);
//-> HTML is not added to the fragment

div.innerHTML = html;
//-> Error (expected, but I tried it anyway)

var doc = new ActiveXObject("htmlfile");
doc.write(html);
doc.close();
//-> JavaScript executes

También he intentado extraer la <head> y <body>nodos desde el HTML y agregar a una <HTML> elemento en el interior del fragmento, aún sin suerte.

¿Alguien tiene alguna idea?

  • I don't want to use libraries (like jQuery). There's too much bloat for what I need to do here siempre hay el compilador de cierre: stackoverflow.com/questions/1691861/…
  • Mendes: un iframe iba a ejecutar el script y IE7 no tiene métodos para la zona de pruebas, excepto la security atributo que no es garantía de que el script no se ejecuta.
  • Solo voy a decir la palabra de la Hta (sobre los que no sé nada), pegue el siguiente link y retiro. Hay una buena probabilidad de que sea completamente inútil. msdn.microsoft.com/en-us/library/ms536496%28v=vs.85%29.aspx
  • Que las versiones de IE? He ejecutado en los problemas de procesamiento donde Tridente no rendir algo que se carga en el valor de innerHTML en 6/7. Este comportamiento ocurre cuando se utiliza un inadecuado método DOM para hacer algo.
  • Muy relacionado con: el Análisis de una cadena HTML utilizando DOMParser con tipo MIME text/html: JavaScript DOMParser acceso innerHTML y otras propiedades.
InformationsquelleAutor Andy E | 2011-09-19

7 Kommentare

  1. 79

    Violín: http://jsfiddle.net/JFSKe/6/

    DocumentFragment no implementar métodos de DOM. El uso de document.createElement en conjunción con innerHTML quita el <head> y <body> etiquetas (incluso cuando se ha creado el elemento es un elemento raíz, <html>). Por lo tanto, la solución debe buscarse en otra parte. He creado un cross-browser cadena-a-DOM función, que hace uso de una invisible línea de la trama.

    Todos los recursos externos y las secuencias de comandos se deshabilitará. Ver Explicación del código para obtener más información.

    Código

    /*
     @param String html    The string with HTML which has be converted to a DOM object
     @param func callback  (optional) Callback(HTMLDocument doc, function destroy)
     @returns              undefined if callback exists, else: Object
                            HTMLDocument doc  DOM fetched from Parameter:html
                            function destroy  Removes HTMLDocument doc.         */
    function string2dom(html, callback){
        /* Sanitise the string */
        html = sanitiseHTML(html); /*Defined at the bottom of the answer*/
    
        /* Create an IFrame */
        var iframe = document.createElement("iframe");
        iframe.style.display = "none";
        document.body.appendChild(iframe);
    
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        doc.open();
        doc.write(html);
        doc.close();
    
        function destroy(){
            iframe.parentNode.removeChild(iframe);
        }
        if(callback) callback(doc, destroy);
        else return {"doc": doc, "destroy": destroy};
    }
    
    /* @name sanitiseHTML
       @param String html  A string representing HTML code
       @return String      A new string, fully stripped of external resources.
                           All "external" attributes (href, src) are prefixed by data- */
    
    function sanitiseHTML(html){
        /* Adds a <!-\"'--> before every matched tag, so that unterminated quotes
            aren't preventing the browser from splitting a tag. Test case:
           '<input style="foo;b:url(0);><input onclick="<input type=button onclick="too() href=;>">' */
        var prefix = "<!--\"'-->";
        /*Attributes should not be prefixed by these characters. This list is not
         complete, but will be sufficient for this function.
          (see http://www.w3.org/TR/REC-xml/#NT-NameChar) */
        var att = "[^-a-z0-9:._]";
        var tag = "<[a-z]";
        var any = "(?:[^<>\"']*(?:\"[^\"]*\"|'[^']*'))*?[^<>]*";
        var etag = "(?:>|(?=<))";
    
        /*
          @name ae
          @description          Converts a given string in a sequence of the
                                 original input and the HTML entity
          @param String string  String to convert
          */
        var entityEnd = "(?:;|(?!\\d))";
        var ents = {" ":"(?:\\s|&nbsp;?|&#0*32"+entityEnd+"|&#x0*20"+entityEnd+")",
                    "(":"(?:\\(|&#0*40"+entityEnd+"|&#x0*28"+entityEnd+")",
                    ")":"(?:\\)|&#0*41"+entityEnd+"|&#x0*29"+entityEnd+")",
                    ".":"(?:\\.|&#0*46"+entityEnd+"|&#x0*2e"+entityEnd+")"};
                    /*Placeholder to avoid tricky filter-circumventing methods*/
        var charMap = {};
        var s = ents[" "]+"*"; /* Short-hand space */
        /* Important: Must be pre- and postfixed by < and >. RE matches a whole tag! */
        function ae(string){
            var all_chars_lowercase = string.toLowerCase();
            if(ents[string]) return ents[string];
            var all_chars_uppercase = string.toUpperCase();
            var RE_res = "";
            for(var i=0; i<string.length; i++){
                var char_lowercase = all_chars_lowercase.charAt(i);
                if(charMap[char_lowercase]){
                    RE_res += charMap[char_lowercase];
                    continue;
                }
                var char_uppercase = all_chars_uppercase.charAt(i);
                var RE_sub = [char_lowercase];
                RE_sub.push("&#0*" + char_lowercase.charCodeAt(0) + entityEnd);
                RE_sub.push("&#x0*" + char_lowercase.charCodeAt(0).toString(16) + entityEnd);
                if(char_lowercase != char_uppercase){
                    RE_sub.push("&#0*" + char_uppercase.charCodeAt(0) + entityEnd);   
                    RE_sub.push("&#x0*" + char_uppercase.charCodeAt(0).toString(16) + entityEnd);
                }
                RE_sub = "(?:" + RE_sub.join("|") + ")";
                RE_res += (charMap[char_lowercase] = RE_sub);
            }
            return(ents[string] = RE_res);
        }
        /*
          @name by
          @description  second argument for the replace function.
          */
        function by(match, group1, group2){
            /* Adds a data-prefix before every external pointer */
            return group1 + "data-" + group2 
        }
        /*
          @name cr
          @description            Selects a HTML element and performs a
                                      search-and-replace on attributes
          @param String selector  HTML substring to match
          @param String attribute RegExp-escaped; HTML element attribute to match
          @param String marker    Optional RegExp-escaped; marks the prefix
          @param String delimiter Optional RegExp escaped; non-quote delimiters
          @param String end       Optional RegExp-escaped; forces the match to
                                      end before an occurence of <end> when 
                                      quotes are missing
         */
        function cr(selector, attribute, marker, delimiter, end){
            if(typeof selector == "string") selector = new RegExp(selector, "gi");
            marker = typeof marker == "string" ? marker : "\\s*=";
            delimiter = typeof delimiter == "string" ? delimiter : "";
            end = typeof end == "string" ? end : "";
            var is_end = end && "?";
            var re1 = new RegExp("("+att+")("+attribute+marker+"(?:\\s*\"[^\""+delimiter+"]*\"|\\s*'[^'"+delimiter+"]*'|[^\\s"+delimiter+"]+"+is_end+")"+end+")", "gi");
            html = html.replace(selector, function(match){
                return prefix + match.replace(re1, by);
            });
        }
        /* 
          @name cri
          @description            Selects an attribute of a HTML element, and
                                   performs a search-and-replace on certain values
          @param String selector  HTML element to match
          @param String attribute RegExp-escaped; HTML element attribute to match
          @param String front     RegExp-escaped; attribute value, prefix to match
          @param String flags     Optional RegExp flags, default "gi"
          @param String delimiter Optional RegExp-escaped; non-quote delimiters
          @param String end       Optional RegExp-escaped; forces the match to
                                      end before an occurence of <end> when 
                                      quotes are missing
         */
        function cri(selector, attribute, front, flags, delimiter, end){
            if(typeof selector == "string") selector = new RegExp(selector, "gi");
            flags = typeof flags == "string" ? flags : "gi";
             var re1 = new RegExp("("+att+attribute+"\\s*=)((?:\\s*\"[^\"]*\"|\\s*'[^']*'|[^\\s>]+))", "gi");
    
            end = typeof end == "string" ? end + ")" : ")";
            var at1 = new RegExp('(")('+front+'[^"]+")', flags);
            var at2 = new RegExp("(')("+front+"[^']+')", flags);
            var at3 = new RegExp("()("+front+'(?:"[^"]+"|\'[^\']+\'|(?:(?!'+delimiter+').)+)'+end, flags);
    
            var handleAttr = function(match, g1, g2){
                if(g2.charAt(0) == '"') return g1+g2.replace(at1, by);
                if(g2.charAt(0) == "'") return g1+g2.replace(at2, by);
                return g1+g2.replace(at3, by);
            };
            html = html.replace(selector, function(match){
                 return prefix + match.replace(re1, handleAttr);
            });
        }
    
        /* <meta http-equiv=refresh content="  ; url= " > */
        html = html.replace(new RegExp("<meta"+any+att+"http-equiv\\s*=\\s*(?:\""+ae("refresh")+"\""+any+etag+"|'"+ae("refresh")+"'"+any+etag+"|"+ae("refresh")+"(?:"+ae(" ")+any+etag+"|"+etag+"))", "gi"), "<!-- meta http-equiv=refresh stripped-->");
    
        /* Stripping all scripts */
        html = html.replace(new RegExp("<script"+any+">\\s*//\\s*<\\[CDATA\\[[\\S\\s]*?]]>\\s*</script[^>]*>", "gi"), "<!--CDATA script-->");
        html = html.replace(/<script[\S\s]+?<\/script\s*>/gi, "<!--Non-CDATA script-->");
        cr(tag+any+att+"on[-a-z0-9:_.]+="+any+etag, "on[-a-z0-9:_.]+"); /* Event listeners */
    
        cr(tag+any+att+"href\\s*="+any+etag, "href"); /* Linked elements */
        cr(tag+any+att+"src\\s*="+any+etag, "src"); /* Embedded elements */
    
        cr("<object"+any+att+"data\\s*="+any+etag, "data"); /* <object data= > */
        cr("<applet"+any+att+"codebase\\s*="+any+etag, "codebase"); /* <applet codebase= > */
    
        /* <param name=movie value= >*/
        cr("<param"+any+att+"name\\s*=\\s*(?:\""+ae("movie")+"\""+any+etag+"|'"+ae("movie")+"'"+any+etag+"|"+ae("movie")+"(?:"+ae(" ")+any+etag+"|"+etag+"))", "value");
    
        /* <style> and < style=  > url()*/
        cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "url", "\\s*\\(\\s*", "", "\\s*\\)");
        cri(tag+any+att+"style\\s*="+any+etag, "style", ae("url")+s+ae("(")+s, 0, s+ae(")"), ae(")"));
    
        /* IE7- CSS expression() */
        cr(/<style[^>]*>(?:[^"']*(?:"[^"]*"|'[^']*'))*?[^'"]*(?:<\/style|$)/gi, "expression", "\\s*\\(\\s*", "", "\\s*\\)");
        cri(tag+any+att+"style\\s*="+any+etag, "style", ae("expression")+s+ae("(")+s, 0, s+ae(")"), ae(")"));
        return html.replace(new RegExp("(?:"+prefix+")+", "g"), prefix);
    }

    Explicación del código

    La sanitiseHTML función se basa en mi replace_all_rel_by_abs función (ver esta respuesta). El sanitiseHTML función es completamente reescrito, aunque, con el fin de lograr la máxima eficiencia y fiabilidad.

    Además, un nuevo conjunto de Regex se agregan a quitar todas las secuencias de comandos y controladores de eventos (incluyendo CSS expression(), IE7-). Para asegurarse de que todas las etiquetas se analiza como se esperaba, el ajustar las etiquetas son precedidos por <!--'"-->. Este prefijo es necesario analizar correctamente anidados «manejadores de eventos» en conjunto con sin comillas: <a id="><input onclick="<div onmousemove=evil()>">.

    Estos Regex se crean de forma dinámica usando una función interna cr/cri (Crear Replace [menline]). Estas funciones aceptan una lista de argumentos, y crear y ejecutar un avanzado RE reemplazo. Para asegurarse de que las entidades HTML no están violando una RegExp (refresh en <meta http-equiv=refresh> podría ser escrito en varias formas), creados dinámicamente Regex son parcialmente construido por la función ae (Unny Entity).

    El real reemplazos se realiza mediante la función by (reemplazar por). En esta implementación, by añade data- antes de todo igualado atributos.

    1. Todos <script>//<[CDATA[ .. //]]></script> apariciones son rayados. Este paso es necesario, porque CDATA secciones permiten </script> cadenas dentro del código. Después de esta sustitución ha sido ejecutado, es seguro para ir a la siguiente sustitución:
    2. El resto de <script>...</script> etiquetas son eliminados.
    3. La <meta http-equiv=refresh .. > etiqueta es removida
    4. Todos detectores de eventos y externos punteros/atributos (href, src, url()) están precedidos por data-, como se describe anteriormente.

    5. Un IFrame objeto es creado. Los IFrames son menos propensas a las fugas de memoria (contrario a la htmlfile ActiveXObject). El IFrame se vuelve invisible, y se anexa el documento, de modo que el DOM se puede acceder. document.write() se utilizan para escribir HTML del IFrame. document.open() y document.close() se utiliza para vaciar el contenido anterior del documento, por lo que el documento generado es una copia exacta de la html cadena.

    6. Si una función de devolución de llamada se ha especificado, la función será llamada con dos argumentos. El primera argumento es una referencia a los generados document objeto. El segundo argumento es una función, que destruye el generado DOM árbol cuando se le llama. Esta función debe ser llamada cuando usted no necesita el árbol más.
      Si la función de devolución de llamada no está especificado, la función devuelve un objeto compuesto de dos propiedades (doc y destroy), que se comportan de la misma como los ya mencionados argumentos.

    Notas adicionales

    • Configuración de la designMode de propiedad «Sobre» dejará un marco de ejecución de secuencias de comandos (no se admite en Chrome). Si usted preserve la <script> etiquetas por un motivo específico, puede utilizar iframe.designMode = "On" en lugar de la secuencia de comandos de desencofrado característica.
    • Yo no era capaz de encontrar una fuente fiable para la htmlfile activeXObject. De acuerdo a esta fuente, htmlfile es más lento que IFrames, y más susceptibles a pérdidas de memoria.
    • Todos los atributos afectados (href, src, …) están precedidos por data-. Un ejemplo de obtener/cambiar estos atributos se muestra para data-href:
      elem.getAttribute("data-href") y elem.setAttribute("data-href", "...")
      elem.dataset.href y elem.dataset.href = "...".
    • Recursos externos han sido deshabilitadas. Como resultado, la página puede parecer completamente diferentes:
      <link href="main.css" /> No externo estilos
      <script>document.body.bgColor="red";</script> No hay secuencias de comandos estilos
      <img src="128x128.png" /> Sin imágenes: el tamaño del elemento, pueden ser completamente diferentes.

    Ejemplos

    sanitiseHTML(html)

    Pegar este bookmarklet en la ubicación de la barra. Se ofrecerá una opción para inyectar un textarea, mostrando la depurada cadena HTML.

    javascript:void(function(){var s=document.createElement("script");s.src="http://rob.lekensteyn.nl/html-sanitizer.js";document.body.appendChild(s)})();

    Ejemplos de código – string2dom(html):

    string2dom("<html><head><title>Test</title></head></html>", function(doc, destroy){
        alert(doc.title); /* Alert: "Test" */
        destroy();
    });
    
    var test = string2dom("<div id='secret'></div>");
    alert(test.doc.getElementById("secret").tagName); /* Alert: "DIV" */
    test.destroy();

    Notables referencias

    • +1 de mí, demasiado. Yo ya había llegado a las mismas conclusiones con respecto a los fragmentos (después de una amplia investigación y pruebas). La parte interesante es la configuración de designMode a on para evitar la ejecución del script. De todos modos, muchas gracias… esto es más el tipo de respuesta que yo buscaba. La única lástima es que muchas de las posibles agujeros, así que hay que darle a esto un poco más de pensamiento.
    • Véase el punto 3 (+ la correspondiente función replace) y las dos primeras referencias al final. Si usted está absolutamente seguro de que una determinada etiqueta (<applet>?) no aparecen, no hay necesidad de implementarlo. Si usted no tiene que mantener los elementos incrustados para un objetivo específico, de la eliminación de ellos a través de una RE es fácil. Ej.: .replace(/<object[\S\s]+?<\/object\s*>/gi, ""). Algunos objetos incrustados pueden tener un omitido cierre de la etiqueta. En ese caso, utilice: .replace(/<embed[^>]+>[\S\s]*?<\/embed\s*>/gi, "").replace(/<embed[^>]*>/gi, "").
    • Actualmente estoy en una etapa avanzada de desarrollo de una función fiable para analizar fuentes externas. Qué importa si (por ejemplo) el src atributo tiene que ser de referencia a través de data-src en lugar de src? Yo podría modificar nativo Element objetos, aunque no son muy fiables.
    • +1 Gran respuesta. También podría ser valiosa para solucionar <stylesheet> y/o <style>? Que podría tener expressions o -moz-behaviors.
    • La adición de filtros para behavior, -moz-binding o expression() rara vez conducen a los resultados deseados, porque de estilo externas no pueden ser validados (a menos que todos los recursos a través de un proxy) JS-proxy basado en: ver el tercer número en mi perfil de la lista.
    • Supongo que en realidad no importa. -moz-binding no es aplicable a mí y designMode debe detener cualquier expresiones de la ejecución.
    • ¿Cuál es tu respuesta con respecto a «Qué importa si (por ejemplo) el atributo src tiene que ser de referencia a través de data-src en lugar de src? (4 comentarios antes de este).
    • no, no creo que los problemas.
    • Me refería a cambiar el href a data-href y quitar <style>s en total. Sí proxing la <stylsheet>s sería realmente molesto 😉
    • href=»http://jsfiddle.net/JFSKe/2/» >jsfiddle.net/JFSKe/2 es un trivial de ataque en el desinfectante. Sé de al menos una forma trivial a la derrota y no estoy ni siquiera vagamente, un XSS experto.
    • He actualizado mi respuesta, y combinado mi solución para esta pregunta con el anterior string2dom función. @Alohci revisar mi código nuevo 😉
    • un análisis rápido sobre el código indica que, si está presente, el <base> etiqueta no es honrado por aquellos direcciones Url relativas.
    • El código no parece ser de desinfección en* atributos correctamente ahora. Esta entrada "<html><head><title>Test</title></head><body onload='alert(\"XSS\")'></html>" muestra un «XSS» alerta. Recomiendo fuertemente que usted construye un muy completo paquete de prueba.
    • Cambio on a on[-a-z0-9:_.]+. El detector de eventos selector de ahora correctamente ser reemplazado. @AndyE, <base> etiquetas son seleccionados a través de la href RE.
    • Intente esto: "<html><head><title>Test</title></head><body onx='>' onload='alert(\"XSS\")'></html>"
    • Gracias. He «sólo» reescrito mi sanitiseHTML función.
    • Con respecto a su edición. He revertido tu edición, debido a que el espacio en blanco entre los elementos de la lista están destinados. Se separan los bloques en diferentes secciones.
    • He utilizado el puro iframe truco y se sorprendió al descubrir que no siempre fue sincrónica en Chrome 46! Al analizar una página compleja, de hecho tuve que esperar (setTimeout) antes de la <body> elemento apareció en el interior de la DOM. Es de suponer que la página quería cargar algo a través de la red antes de que pudiera darse cuenta plenamente. Sin embargo en Firefox fue sincrónico.

  2. 4

    No sé por qué estás jugando con documentFragments, sólo puede establecer el texto HTML como el innerHTML de un nuevo elemento div. A continuación, puede utilizar ese elemento div para getElementsByTagName etc sin la adición de la div a DOM:

    var htmlText= '<html><head><title>Test</title></head><body><div id="test_ele1">this is test_ele1 content</div><div id="test_ele2">this is test_ele content2</div></body></html>';
    
    var d = document.createElement('div');
    d.innerHTML = htmlText;
    
    console.log(d.getElementsByTagName('div'));

    Si realmente estás casado con la idea de un documentFragment, puede utilizar este código, pero usted todavía tiene que envolver en un div para obtener el DOM funciones que está después de:

    function makeDocumentFragment(htmlText) {
        var range = document.createRange();
        var frag = range.createContextualFragment(htmlText);
        var d = document.createElement('div');
        d.appendChild(frag);
        return d;
    }
    • Esto elimina el <head> elemento antes de anexar a la recién creada div. Yo sé que yo no especificar que necesito cosas de la cabeza demasiado, pero tengo que hacer (específicamente <link> elementos). Estoy jugando con fragmentos de documento como parece el método más probable de trabajar si esto es posible. createContextualFragment no me ayuda, no se admite en el IE.
    • He investigado un poco – sin acceso a cosas como developer.mozilla.org/En/DOM/DOMImplementation.createDocument y sin el uso de un iFrame, en realidad no hay otra manera de hacer esto estrictamente el lado del cliente. No estaba seguro acerca de la compatibilidad con la Gama/createContextualFragment en IE 7, pero después me puse a mirar en los resultados me di cuenta de que no es diferente de simplemente acercándose mucho a la de HTML en un nuevo elemento div. Desde fragmentos de documento no tiene el DOM funciones que desea y divs no puede válidamente contener HTML/CUERPO, no estoy seguro de cuál es la opción que tienen.
  3. 2

    No estoy seguro de si IE apoya document.implementation.createHTMLDocument, pero si lo hace, el uso de este algoritmo (adaptado de mi DOMParser extensión HTML). Tenga en cuenta que el DOCTYPE no se conservan.:

    var
          doc = document.implementation.createHTMLDocument("")
        , doc_elt = doc.documentElement
        , first_elt
    ;
    doc_elt.innerHTML = your_html_here;
    first_elt = doc_elt.firstElementChild;
    if ( //are we dealing with an entire document or a fragment?
           doc_elt.childElementCount === 1
        && first_elt.tagName.toLowerCase() === "html"
    ) {
        doc.replaceChild(first_elt, doc_elt);
    }
    
    //doc is an HTML document
    //you can now reference stuff like doc.title, etc.
    • IE 9 es compatible con él, pero IE 8 e inferiores no, por desgracia.
  4. 1

    Suponiendo que el HTML XML válido también, usted puede utilizar loadXML()

    • Yo no puedo asumir que, por desgracia. El HTML cargado podría (en teoría) ser de cualquier sitio en la web.
  5. 0

    DocumentFragment no admite getElementsByTagName — que sólo se admite por Document.

    Puede necesitar el uso de una biblioteca como jsdom, que proporciona una implementación de la DOM y a través del cual usted puede buscar usando getElementsByTagName y otras DOM Api. Y puedes configurarlo para no ejecutar secuencias de comandos. Sí, es pesado » y no sé si funciona en IE 7.

    • Interesante… es decir soporta getElementsByTagName de fragmentos de documento (que es lo que yo basa en que punto de mi pregunta).
    • Extraño, pero supongo que no debería sorprendernos que el IE no cumple con las especificaciones. Here una discusión que implica que createDocumentFragment en IE, en realidad crea un Document en lugar de DocumentFragment, lo cual explicaría por qué se admite getElementsByTagName.
  6. 0

    Sólo vagaba a través de esta página, soy un poco tarde para ser de cualquier uso 🙂 pero la siguiente debería ayudar a alguien con un problema similar en el futuro… sin embargo IE7/8 que en realidad debería ser ignorado por ahora y hay mucho mejores métodos soportados por los navegadores más modernos.

    Las siguientes obras a través de casi todo lo que he probado, los únicos dos lados hacia abajo son:

    1. He añadido a la medida getElementById y getElementsByName funciones de la raíz del elemento div, por lo que estos no aparecen como se esperaba más abajo en el árbol (a menos que el código es modificado para atender a este).

    2. El doctype será ignorado -, sin embargo no creo que este va a hacer mucha diferencia como mi experiencia es que el doctype no efecto de cómo el dom se estructura, cómo se representa (que obviamente no sucede con este método).

    Básicamente, el sistema se basa en el hecho de que <tag> y <namespace:tag> son tratados de manera diferente por el useragents. Como ha sido encontrado algunas etiquetas especiales no pueden existir dentro de un elemento div, y por lo tanto, se eliminan. Nombres de espacios de elementos puede ser colocado en cualquier lugar (a menos que exista una DTD donde se indique lo contrario). Mientras que estos espacio de nombres de etiquetas en realidad no se comportan como los tags real en cuestión, teniendo en cuenta que sólo son realmente el uso de ellos por su posición estructural en el documento que en realidad no causar un problema.

    de marcado y código son como sigue:

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    
      ///function for parsing HTML source to a dom structure
      ///Tested in Mac OSX, Win 7, Win XP with FF, IE 7/8/9, 
      ///Chrome, Safari & Opera.
      function parseHTML(src){
    
        ///create a random div, this will be our root
        var div = document.createElement('div'),
            ///specificy our namespace prefix
            ns = 'faux:',
            ///state which tags we will treat as "special"
            stn = ['html','head','body','title'];
            ///the reg exp for replacing the special tags
            re = new RegExp('<(/?)('+stn.join('|')+')([^>]*)?>','gi'),
            ///remember the getElementsByTagName function before we override it
            gtn = div.getElementsByTagName;
    
        ///a quick function to namespace certain tag names
        var nspace = function(tn){
          if ( stn.indexOf ) {
            return stn.indexOf(tn) != -1 ? ns + tn : tn;
          }
          else {
            return ('|'+stn.join('|')+'|').indexOf(tn) != -1 ? ns + tn : tn;
          }
        };
    
        ///search and replace our source so that special tags are namespaced
        ///&nbsp; required for IE7/8 to render tags before first text found
        ///<faux:check /> tag added so we can test how namespaces work
        src = '&nbsp;<'+ns+'check />' + src.replace(re,'<$1'+ns+'$2$3>');
        ///inject to the div
        div.innerHTML = src;
        ///quick test to see how we support namespaces in TagName searches
        if ( !div.getElementsByTagName(ns+'check').length ) {
          ns = '';
        }
    
        ///create our replacement getByName and getById functions
        var createGetElementByAttr = function(attr, collect){
          var func = function(a,w){
            var i,c,e,f,l,o; w = w||[];
            if ( this.nodeType == 1 ) {
              if ( this.getAttribute(attr) == a ) {
                if ( collect ) {
                  w.push(this);
                }
                else {
                  return this;
                }
              }
            }
            else {
              return false;
            }
            if ( (c = this.childNodes) && (l = c.length) ) {
              for( i=0; i<l; i++ ){
                if( (e = c[i]) && (e.nodeType == 1) ) {
                  if ( (f = func.call( e, a, w )) && !collect ) {
                    return f;
                  }
                }
              }
            }
            return (w.length?w:false);
          }
          return func;
        }
    
        ///apply these replacement functions to the div container, obviously 
        ///you could add these to prototypes for browsers the support element 
        ///constructors. For other browsers you could step each element and 
        ///apply the functions through-out the node tree... however this would  
        ///be quite messy, far better just to always call from the root node - 
        ///or use div.getElementsByTagName.call( localElement, 'tag' );
        div.getElementsByTagName = function(t){return gtn.call(this,nspace(t));}
        div.getElementsByName    = createGetElementByAttr('name', true);
        div.getElementById       = createGetElementByAttr('id', false);
    
        ///return the final element
        return div;
      }
    
      window.onload = function(){
    
        ///parse the HTML source into a node tree
        var dom = parseHTML( document.getElementById('source').innerHTML );
    
        ///test some look ups :)
        var a = dom.getElementsByTagName('head'),
            b = dom.getElementsByTagName('title'),
            c = dom.getElementsByTagName('script'),
            d = dom.getElementById('body');
    
        ///alert the result
        alert(a[0].innerHTML);
        alert(b[0].innerHTML);
        alert(c[0].innerHTML);
        alert(d.innerHTML);
    
      }
    </script>
    </head>
    <body>
      <xmp id="source">
        <!DOCTYPE html>
        <html>
        <head>
          <!-- Comment //-->
          <meta charset="utf-8">
          <meta name="robots" content="index, follow">
          <title>An example</title>
          <link href="test.css" />
          <script>alert('of parsing..');</script>
        </head>
        <body id="body">
          <b>in a similar way to createDocumentFragment</b>
        </body>
        </html>
      </xmp>
    </body>
    </html>
  7. 0

    Completo HTML DOM habilidades sin activación de solicitudes, sin tener que lidiar con incompatibilidades:

    var doc = document.cloneNode();
    if (!doc.documentElement) {
        doc.appendChild(doc.createElement('html'));
        doc.documentElement.appendChild(doc.createElement('head'));
        doc.documentElement.appendChild(doc.createElement('body'));
    }

    Conjunto de todos ! doc es un documento html, pero no es en línea.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea