Obtener la representación de cadena de un nodo DOM

96

Javascript: tengo la representación DOM de un nodo (elemento o documento) y estoy buscando la representación de cadena del mismo. P.ej,

var el = document.createElement("p");
el.appendChild(document.createTextNode("Test"));

debería producir:

get_string(el) == "<p>Test</p>";

Tengo la fuerte sensación de que me falta algo trivialmente simple, pero simplemente no encuentro un método que funcione en IE, FF, Safari y Opera. Por lo tanto, externalHTML no es una opción.

Boldewyn
fuente
4
Con presumiblemente versión de Firefox 11 también soporta outerHTML: bugzilla.mozilla.org/show_bug.cgi?id=92264
Boldewyn
1
Por ahora, parece que IE, FF, Safari, Chrome, Opera son compatibles con HTML externo, consulte developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML
wangf
1
Sí, ahora (desde 2009, es decir) se ha convertido en una tarea trivial :)
Boldewyn
Sí, definitivamente HTML externo
neaumusic

Respuestas:

133

Puede crear un nodo principal temporal y obtener su contenido innerHTML:

var el = document.createElement("p");
el.appendChild(document.createTextNode("Test"));

var tmp = document.createElement("div");
tmp.appendChild(el);
console.log(tmp.innerHTML); // <p>Test</p>

EDITAR: Consulte la respuesta a continuación sobre HTML externo. el.outerHTML debería ser todo lo que se necesita.

CMS
fuente
1
Ay. Tan simple ... Solo una pequeña nota: si quiero que todo el documento esté "en cadena", puedo usar el mismo método con document.documentElement (caso de uso: solicitudes AJAX). ¿Quizás podrías incorporar eso en la respuesta?
Boldewyn
3
@Boldewyn: ¿puedes agregar todo document.documentElementa un div? Santa mierda ....
Roatin Marth
Simple, como el infierno ... +1 Lástima documentFragment no admite innerHTML
Lajos Meszaros
30
externalHTML es la respuesta
neaumusic
3
No olvide clonar su elementantes de agregarlo tmpporque cuando lo agregue tmp, se eliminará de document.
Olcay Ertaş
44

Lo que está buscando es 'externalHTML', pero necesitamos un respaldo porque no es compatible con los navegadores antiguos.

var getString = (function() {
  var DIV = document.createElement("div");

  if ('outerHTML' in DIV)
    return function(node) {
      return node.outerHTML;
    };

  return function(node) {
    var div = DIV.cloneNode();
    div.appendChild(node.cloneNode(true));
    return div.innerHTML;
  };

})();

// getString(el) == "<p>Test</p>"

Encontrarás mi complemento jQuery aquí: Obtener el HTML externo del elemento seleccionado

gtournie
fuente
Firefox agregado outerHTMLen la versión 11, después de que hice la pregunta. Entonces esa no era una opción en ese entonces. Incluso actualicé mi pregunta con un comentario apropiado, si miras de cerca.
Boldewyn
Esto es correcto, porque suelta los ID de elementos y otros atributos si los usainnerHtml
Sergei Panfilov
1
@SergeyPanfilov: No solté nada porque envolví el nodo en un div vacío antes de llamar innerHTML; )
gtournie
3
En 2015, diría que esta es de lejos la mejor respuesta.
ACK_stoverflow
Sí, a partir de hoy, solo los navegadores muy antiguos (IE> 10, Safari> 7, FF verdaderamente antiguo, Chrome) y / o los navegadores poco conocidos (Opera Mini) no admiten el outerHTMLatributo. Ver también caniuse.com/#feat=xml-serializer
Gert Sønderby
20

No creo que necesites ningún guión complicado para esto. Solo usa

get_string=(el)=>el.outerHTML;
Shishir Arora
fuente
esta es la mejor respuesta
Avraham
15

En FF puede utilizar el XMLSerializerobjeto para serializar XML en una cadena. IE te da una xmlpropiedad de nodo. Entonces puedes hacer lo siguiente:

function xml2string(node) {
   if (typeof(XMLSerializer) !== 'undefined') {
      var serializer = new XMLSerializer();
      return serializer.serializeToString(node);
   } else if (node.xml) {
      return node.xml;
   }
}
Bryan Kyle
fuente
Para su información .xml, no funciona en los nodos DOM (como en los nodos de la página actual). Solo funciona en nodos de documentos XML DOM.
Crescent Fresh
Y a la inversa, outerHTMLno funciona en los nodos de documentos DOM XML. Solo funciona en nodos DOM (como en los nodos de la página actual). Buena consistencia, diría yo.
Crescent Fresh
7

Utilice el elemento # externalHTML:

var el = document.createElement("p");
el.appendChild(document.createTextNode("Test"));

console.log(el.outerHTML);

También se puede utilizar para escribir elementos DOM. De la documentación de Mozilla:

El atributo externalHTML de la interfaz DOM del elemento obtiene el fragmento HTML serializado que describe el elemento, incluidos sus descendientes. Se puede configurar para reemplazar el elemento con nodos analizados a partir de la cadena dada.

https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML

Rico Apodaca
fuente
3

Utilice element.outerHTML para obtener una representación completa del elemento, incluidas las etiquetas y los atributos externos.

Pavel V.
fuente
1

Si tu elemento tiene padre

element.parentElement.innerHTML
Vincnetas
fuente
2
¡Gracias por la respuesta! Desafortunadamente, eso ya se sugirió, pero el que respondió eliminó la respuesta. El problema es que el padre puede contener mucho más marcado del deseado. Piense en externalHTML para uno <li>en una lista.
Boldewyn
1

Tratar

new XMLSerializer().serializeToString(element);
Alex Popa
fuente
Gracias por la sugerencia, pero eso es exactamente lo que sugirió Bryan Kale en su respuesta.
Boldewyn
1

Descubrí que para mis casos de uso no siempre quiero el HTML externo completo. Muchos nodos simplemente tienen demasiados hijos para mostrar.

Aquí hay una función (mínimamente probada en Chrome):

/**
 * Stringifies a DOM node.
 * @param {Object} el - A DOM node.
 * @param {Number} truncate - How much to truncate innerHTML of element.
 * @returns {String} - A stringified node with attributes
 *                     retained.
 */
function stringifyEl(el, truncate) {
    var truncateLen = truncate || 50;
    var outerHTML = el.outerHTML;
    var ret = outerHTML;
    ret = ret.substring(0, truncateLen);

    // If we've truncated, add an elipsis.
    if (outerHTML.length > truncateLen) {
      ret += "...";
    }
    return ret;
}

https://gist.github.com/kahunacohen/467f5cc259b5d4a85eb201518dcb15ec

Aaron
fuente
0

He perdido mucho tiempo averiguando qué está mal cuando itero a través de DOMElements con el código en la respuesta aceptada. Esto es lo que funcionó para mí, de lo contrario, cada segundo elemento desaparece del documento:

_getGpxString: function(node) {
          clone = node.cloneNode(true);
          var tmp = document.createElement("div");
          tmp.appendChild(clone);
          return tmp.innerHTML;
        },
Balagan
fuente
1
No me arriesgo, cuando supongo, que tienes un problema diferente aquí. Tenga en cuenta que la solución anterior elimina el elemento original del DOM. Entonces, cuando usa una colección en vivo como document.getElementsByTagName(), esa colección cambiará en medio del forciclo, por lo tanto, se saltará cada segundo elemento.
Boldewyn
-1

si usa reaccionar:

const html = ReactDOM.findDOMNode(document.getElementsByTagName('html')[0]).outerHTML;
victorkurauchi
fuente
.outerHTMLno es específico de React; es un estándar DOM. Mira la respuesta de @Rich Apodaca.
chharvey
sí ... el punto de interés (si usa react) en mi respuesta fue reactdom.findDOMNode()..., no el .outerHTML, pero gracias por la posición
victorkurauchi