Получить строковое представление узла DOM

97

Javascript: у меня есть представление DOM узла (элемента или документа), и я ищу его строковое представление. Например,

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

должен дать:

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

У меня есть сильное чувство, что мне не хватает чего-то банально простого, но я просто не нашел метода, который работал бы в IE, FF, Safari и Opera. Следовательно, externalHTML - не вариант.

Болдевин
источник
4
Предположительно, версия 11 Firefox также поддерживает externalHTML: bugzilla.mozilla.org/show_bug.cgi?id=92264
Boldewyn
1
На данный момент, выглядит IE, FF, Safari, Chrome, Opera все поддерживают outerHTML, см developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML
wangf
1
Да, это теперь (то есть с 2009 года) стало тривиальной задачей :)
Болдевин
Да, определенно externalHTML
neaumusic

Ответы:

134

Вы можете создать временный родительский узел и получить его внутреннее HTML-содержимое:

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>

РЕДАКТИРОВАТЬ: см. Ответ ниже о externalHTML. el.outerHTML должен быть всем, что нужно.

Кристиан К. Сальвадо
источник
1
Ой. Так просто ... Небольшое примечание: если я хочу, чтобы весь документ был "структурирован", я могу использовать тот же метод с document.documentElement (вариант использования: запросы AJAX). Возможно, вы могли бы включить это в ответ?
Boldewyn
3
@Boldewyn: вы можете добавить все document.documentElementв div?
Черт побери
Просто, черт возьми ... +1 Жаль, что documentFragment не поддерживает innerHTML
Лайош Месарош
30
externalHTML - это ответ
neaumusic
3
Не забудьте клонировать свой, elementпрежде чем добавлять его, tmpпотому что при добавлении tmpон будет удален из document.
Olcay Ertaş
45

То, что вы ищете, это 'externalHTML', но нам нужен запасной вариант, потому что он несовместим со старыми браузерами.

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

Здесь вы найдете мой плагин jQuery: Получить внешний HTML-код выбранного элемента

gtournie
источник
Firefox добавлен outerHTMLв версии 11 после того, как я задал вопрос. Так что тогда это был не вариант. Я даже свой вопрос обновил соответствующим комментарием, если присмотреться.
Boldewyn
Это верно, потому что вы теряете идентификаторы элементов и другие атрибуты, если используетеinnerHtml
Сергей Панфилов
1
@SergeyPanfilov: Я ничего не уронил, потому что перед вызовом я обернул узел в пустой div innerHTML; )
gtournie
3
В 2015 году я бы сказал, что это, безусловно, лучший ответ.
ACK_stoverflow
Да, на сегодняшний день только очень старые (IE> 10, Safari> 7, действительно древний FF, Chrome) и / или малоизвестные браузеры (Opera Mini) не поддерживают этот outerHTMLатрибут. См. Также caniuse.com/#feat=xml-serializer
Герт Сёндерби,
20

Не думаю, что для этого нужен сложный сценарий. Просто используйте

get_string=(el)=>el.outerHTML;
Шишир Арора
источник
это лучший ответ
Авраам
15

В FF вы можете использовать XMLSerializerобъект для сериализации XML в строку. IE дает вам xmlсвойство узла. Итак, вы можете сделать следующее:

function xml2string(node) {
   if (typeof(XMLSerializer) !== 'undefined') {
      var serializer = new XMLSerializer();
      return serializer.serializeToString(node);
   } else if (node.xml) {
      return node.xml;
   }
}
Брайан Кайл
источник
FYI .xmlне работает с узлами DOM (как с узлами на текущей странице). Он работает только с узлами документов XML DOM.
Crescent Fresh
И наоборот, outerHTMLне работает с узлами документа XML DOM. Он работает только с узлами DOM (как с узлами на текущей странице). Я бы сказал, хорошая последовательность.
Crescent Fresh
7

Используйте Element # outerHTML:

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

console.log(el.outerHTML);

Его также можно использовать для написания элементов DOM. Из документации Mozilla:

Атрибут outerHTML интерфейса DOM элемента получает сериализованный фрагмент HTML, описывающий элемент, включая его потомков. Его можно настроить для замены элемента узлами, извлеченными из данной строки.

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

Рич Аподака
источник
3

Используйте element.outerHTML, чтобы получить полное представление элемента, включая внешние теги и атрибуты.

Павел В.
источник
1

Если у вашего элемента есть родитель

element.parentElement.innerHTML
Винцнетас
источник
2
Спасибо за ответ! К сожалению, это уже было предложено, но ответчик удалил ответ. Проблема в том, что родительский объект может содержать намного больше разметки, чем хотелось бы. Подумайте о externalHTML для одного<li> в списке.
Boldewyn 02
1

Пытаться

new XMLSerializer().serializeToString(element);
Алекс Попа
источник
Спасибо за предложение, но это именно то, что Брайан Кейл предложил в своем ответе.
Boldewyn 06
1

Я обнаружил, что для моих вариантов использования мне не всегда нужен весь внешний HTML. У многих узлов слишком много потомков, чтобы их можно было показать.

Вот функция (минимально протестированная в 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

Аарон
источник
0

Я потратил много времени, выясняя, что не так, когда я перебираю DOMElements с кодом в принятом ответе. Это то, что у меня сработало, иначе каждый второй элемент исчезнет из документа:

_getGpxString: function(node) {
          clone = node.cloneNode(true);
          var tmp = document.createElement("div");
          tmp.appendChild(clone);
          return tmp.innerHTML;
        },
Балаган
источник
1
Я не рискую, когда предполагаю, что у вас здесь другая проблема. Обратите внимание, что приведенное выше решение удаляет исходный элемент из DOM. Итак, когда вы используете живую коллекцию, например document.getElementsByTagName(), эта коллекция будет меняться в середине forцикла, следовательно, каждый второй элемент пропускается.
Boldewyn
-1

при использовании реакции:

const html = ReactDOM.findDOMNode(document.getElementsByTagName('html')[0]).outerHTML;
Victorkurauchi
источник
.outerHTMLне зависит от React; это стандарт DOM. Посмотрите ответ @Rich Apodaca.
chharvey
да ... интересным моментом (при использовании реакции) в моем ответе было reactdom.findDOMNode()... не то .outerHTML, но спасибо за позицию.
victorkurauchi