Uzyskaj ciąg reprezentujący węzeł DOM

97

JavaScript: Mam reprezentację DOM węzła (elementu lub dokumentu) i szukam reprezentacji ciągu. Na przykład,

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

powinno dać:

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

Mam silne przeczucie, że brakuje mi czegoś trywialnie prostego, ale po prostu nie znajduję metody, która działa w IE, FF, Safari i Opera. Dlatego zewnętrznyHTML nie jest opcją.

Boldewyn
źródło
4
Prawdopodobnie w wersji 11 Firefox obsługuje również zewnętrzną wersję HTML: bugzilla.mozilla.org/show_bug.cgi?id=92264
Boldewyn,
1
Na razie wygląda IE, FF, Safari, Chrome, Opera wszystkie obsługują zewnętrzną HTML, patrz developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML
wangf
1
Tak, teraz (czyli od 2009 roku) stało się to trywialnym zadaniem :)
Boldewyn 22.04.15
Tak, zdecydowanie externalHTML
neaumusic

Odpowiedzi:

134

Możesz utworzyć tymczasowy węzeł nadrzędny i pobrać jego zawartość 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>

EDYCJA: Zobacz odpowiedź poniżej na temat externalHTML. el.outerHTML powinien być wszystkim, czego potrzeba.

Christian C. Salvadó
źródło
1
Auć. To takie proste ... Tylko mała uwaga: jeśli chcę, aby cały dokument został poddany „stringifikacji”, mogę użyć tej samej metody z document.documentElement (przypadek użycia: żądania AJAX). Może mógłbyś uwzględnić to w odpowiedzi?
Boldewyn
3
@Boldewyn: możesz dołączyć całość document.documentElementdo elementu DIV?
Cholera
Proste, jak cholera ... +1 Szkoda documentFragment nie obsługuje innerHTML
Lajos Meszaros
30
Odpowiedź brzmi:
externalHTML
3
Nie zapomnij sklonować swojego elementprzed dodaniem, tmpponieważ kiedy dodasz go do tmp, zostanie usunięty z document.
Olcay Ertaş
45

To, czego szukasz, to „externalHTML”, ale potrzebujemy rozwiązania zastępczego, ponieważ nie jest ono zgodne ze starymi przeglądarkami.

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>"

Znajdziesz moją wtyczkę jQuery tutaj: Pobierz zewnętrzny kod HTML wybranego elementu

gtournie
źródło
Firefox został dodany outerHTMLw wersji 11, po tym, jak zadałem pytanie. Więc to nie było wtedy możliwe. Zaktualizowałem nawet moje pytanie odpowiednim komentarzem, jeśli przyjrzysz się uważnie.
Boldewyn
Zgadza się, bo upuszczasz identyfikatory elementów i inne atrybuty, jeśli używaszinnerHtml
Sergei Panfilov
1
@SergeyPanfilov: Niczego nie upuściłem, ponieważ przed wywołaniem zawiniłem węzeł w pusty element div innerHTML; )
gtournie
3
W 2015 roku powiedziałbym, że to zdecydowanie najlepsza odpowiedź.
ACK_stoverflow
Tak, na dzień dzisiejszy tylko bardzo stare (IE> 10, Safari> 7, prawdziwie starożytne FF, Chrome) i / lub mało znane przeglądarki (Opera Mini) nie obsługują tego outerHTMLatrybutu. Zobacz także caniuse.com/#feat=xml-serializer
Gert Sønderby
20

Myślę, że nie potrzebujesz do tego żadnego skomplikowanego skryptu. Po prostu użyj

get_string=(el)=>el.outerHTML;
Shishir Arora
źródło
to najlepsza odpowiedź
Avraham
15

W FF możesz użyć XMLSerializerobiektu do serializacji XML do łańcucha. IE udostępnia xmlwłaściwość węzła. Możesz więc wykonać następujące czynności:

function xml2string(node) {
   if (typeof(XMLSerializer) !== 'undefined') {
      var serializer = new XMLSerializer();
      return serializer.serializeToString(node);
   } else if (node.xml) {
      return node.xml;
   }
}
Bryan Kyle
źródło
FYI .xmlnie działa na węzłach DOM (tak jak w węzłach na bieżącej stronie). Działa tylko na węzłach dokumentów XML DOM.
Crescent Fresh
I odwrotnie, outerHTMLnie działa na węzłach dokumentów XML DOM. Działa tylko na węzłach DOM (jak w węzłach na bieżącej stronie). Powiedziałbym, że dobra konsystencja.
Crescent Fresh
7

Użyj elementu # externalHTML:

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

console.log(el.outerHTML);

Może być również używany do pisania elementów DOM. Z dokumentacji Mozilli:

Atrybut externalHTML elementu interfejsu DOM pobiera zserializowany fragment HTML opisujący element, w tym jego potomków. Można ustawić, aby zastąpić element węzłami przeanalizowanymi z podanego ciągu.

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

Rich Apodaca
źródło
3

Użyj element.outerHTML, aby uzyskać pełną reprezentację elementu, w tym zewnętrzne znaczniki i atrybuty.

Paweł V.
źródło
1

Jeśli twój element ma rodzica

element.parentElement.innerHTML
Vincnetas
źródło
2
Dziękuję za odpowiedź! Niestety było to już zasugerowane, ale osoba odpowiadająca usunęła odpowiedź. Problem polega na tym, że rodzic może zawierać dużo więcej znaczników niż chciał. Pomyśl o zewnętrznymHTML dla pojedynczego <li>elementu na liście.
Boldewyn
1

Próbować

new XMLSerializer().serializeToString(element);
Alex Popa
źródło
Dziękuję za sugestię, ale dokładnie to zasugerował Bryan Kale w swojej odpowiedzi.
Boldewyn
1

Odkryłem, że dla moich przypadków użycia nie zawsze chcę mieć cały zewnętrzny HTML. Wiele węzłów ma po prostu zbyt wiele dzieci do pokazania.

Oto funkcja (minimalnie przetestowana w 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
źródło
0

Zmarnowałem dużo czasu, zastanawiając się, co jest nie tak, gdy przechodzę przez DOMElements z kodem w zaakceptowanej odpowiedzi. U mnie to zadziałało, inaczej co drugi element znika z dokumentu:

_getGpxString: function(node) {
          clone = node.cloneNode(true);
          var tmp = document.createElement("div");
          tmp.appendChild(clone);
          return tmp.innerHTML;
        },
balagan
źródło
1
Nie wychodzę z kończyny, kiedy przypuszczam, że masz tu inny problem. Zwróć uwagę, że powyższe rozwiązanie usuwa oryginalny element z DOM. Tak więc, kiedy używasz kolekcji na żywodocument.getElementsByTagName() , takiej jak , ta kolekcja zmieni się w połowie forpętli, stąd pomijanie co drugiego elementu.
Boldewyn
-1

jeśli używasz Reaguj:

const html = ReactDOM.findDOMNode(document.getElementsByTagName('html')[0]).outerHTML;
vicorkurauchi
źródło
.outerHTMLnie jest specyficzne dla Reacta; jest to standard DOM. Sprawdź odpowiedź @Rich Apodaca.
chharvey
tak ... interesującym punktem (jeśli korzystam z Reaguj) na mojej odpowiedzi było reactdom.findDOMNode()... nie .outerHTML, ale dzięki za stanowisko.
Victorkurauchi