Я пытаюсь преобразовать таблицу, чтобы программно удалить некоторые используемые теги, которые мне не нужны. Я написал рекурсивную функцию, которая вызывается для элемента таблицы и вызывает себя для всех дочерних элементов, составляя список этих дочерних элементов и заменяя текущие дочерние элементы этими очищенными дочерними элементами. Однако узлы не добавляются правильно, а вместо этого в выходных данных оказывается строковое представление [object HTMLTableSectionElement] или [object Text].
(Для тех, кто интересуется контекстом: я использую thead, tbody и пару пользовательских тегов для необычной таблицы, но я также хочу иметь возможность нажать кнопку, чтобы скопировать таблицу на страницы Википедии, которые не поддерживают эти теги, поэтому при копировании в буфер обмена мне приходится их удалять, иначе это будет выглядеть ужасно)
Это моя функция:
function prepHTMLforExport(element){
//recursively goes into an HTML element, preparing it for export by:
//removing thead and tbody statements but leaving their contents in the parent element
//removing floattext tags
//replacing hyperlink a tags with ...
//go through child elements and prep each for export
var newchildren = []
var children = element.childNodes
for (var i=0;i<children.length;i++){
var newkid = prepHTMLforExport(children[i])
//if the new kid is actually a list, concat the lists
if (newkid instanceof Array){
newchildren.concat(newkid)
} else {
newchildren.push(newkid)
}
}
//if to be removed, return a list of children
if (element.tagName in ["floattext", "table-body", "table-head"]){
return newchildren
} else {
//else add children to self and return self
if (newchildren.length > 0) {
element.replaceChildren(newchildren)
}
return element
}
}
Он должен работать практически с любой таблицей HTML.
Первоначально я подозревал, что проверяю не тех дочерних элементов или использую неправильный метод для их замены, поэтому я также попробовал это с помощью var children = element.children и посмотрел, есть ли другая функция для замены, например replaceWith, но при ближайшем рассмотрении я обнаружил, что это не помогло. Элементы уже преобразуются в неправильную форму в нодлисте своих родителей во время их обработки, а не только после того, как я заменил их очищенной версией. Чтобы проверить это, есть эта таблица:
<table>
<th>sample text</th>
<th>some more sample text</th>
</table>
При прохождении кода, если код только что закончил подготовку первой ячейки, а теперь о рекурсии во вторую ячейку, если вы выполните console.info(element), это приведет к
<table>
<th>[object Text]</th>
<th>some more sample text</th>
</table>
Вероятно, не по теме: array concat — возвращает новый массив, ваш код игнорирует это
Попробуйте изменить на newchildren = newchildren.concat(newkid); и element.replaceChildren(...newchildren) - похоже, работает (по крайней мере, без ошибок): jsfiddle.net/xfnjozhw/1 но вывод выглядит таким же, как ввод, поэтому я понятия не имею, сработало это или нет.
Хм, тогда возникает вопрос, где появляется эта строка и почему... Спасибо за примечание о concat, теперь я исправил это в своем коде.
Ваша проблема в том, что .element.replaceChildren ожидает, что каждый дочерний элемент будет отдельным параметром, однако вы передаете массив. Попробуйте с element.replaceChildren(...newchildren)replaceChildren
@fdomn-m Это действительно работает! Фильтрации пока нет, но мне кажется, это другая проблема. Что именно делает...? это оператор распаковки, такой как python *?
У меня был подготовлен подробный ответ, но я не знал, подойдет ли он вам. Это «остальные параметры», которые преобразуют массив в список параметров. В js также есть оператор распространения, который выглядит так же.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ваша проблема в том, что .element.replaceChildren ожидает, что каждый дочерний элемент будет отдельным параметром, однако вы передаете массив.
Итак, .replaceChildren преобразует массив в строку, давая
[object Text],[object HTMLTableSectionElement]
лишняя запятая , посередине — это дополнительный намек на то, что это был массив, преобразованный в строку.
Вы можете преобразовать массив в параметры, используя остальные параметры — эта строка вашего кода станет:
element.replaceChildren(...newchildren)
Обновленный фрагмент:
function prepHTMLforExport(element) {
//recursively goes into an HTML element, preparing it for export by:
//removing thead and tbody statements but leaving their contents in the parent element
//removing floattext tags
//replacing hyperlink a tags with ...
//go through child elements and prep each for export
var newchildren = []
var children = element.childNodes
for (let i = 0; i < children.length; i++) {
var newkid = prepHTMLforExport(children[i])
//if the new kid is actually a list, concat the lists
if (newkid instanceof Array) {
newchildren = newchildren.concat(newkid);
} else {
newchildren.push(newkid)
}
}
//if to be removed, return a list of children
if (element.tagName in ["floattext", "table-body", "table-head"]) {
return newchildren
} else {
//else add children to self and return self
if (newchildren.length > 0) {
element.replaceChildren(...newchildren);
}
return element
}
}
prepHTMLforExport(document.getElementById("tbl"));<table id='tbl'>
<th>sample text</th>
<th>some more sample text</th>
</table>Помимо массива, упомянутого @fdomn-m в его ответе, я вижу еще три проблемы.
Использование element.childNodes может возвращать текстовые узлы, такие как " " или "\n", а не только узлы элементов. Использование element.children исправит это.
element.tagNames возвращает теги в верхнем регистре, а вы сравниваете их со строками в нижнем регистре.
Наконец, вы сравниваете теги «table-head» и «table-body». Я предполагаю, что вы имели в виду «голова» и «тело». Я не знаю, что такое floattext, который вы проверяете.
Обновлено: Как вы можете видеть в комментариях к коду, я также изменил ваш
в [] быть [].includes()
Вот ваш код со всеми тремя этими изменениями.
function fancyTableOnClick( event ) {
prepHTMLforExport( FancyTableID )
}
function prepHTMLforExport(element){
//recursively goes into an HTML element, preparing it for export by:
//removing thead and tbody statements but leaving their contents in the parent element
//removing floattext tags
//replacing hyperlink a tags with ...
//go through child elements and prep each for export
var newchildren = []
// var children = element.childNodes
var children = element.children // Just elements, no text nodes
for (var i=0;i<children.length;i++){
var newkid = prepHTMLforExport(children[i])
//if the new kid is actually a list, concat the lists
if (newkid instanceof Array){
newchildren = newchildren.concat(newkid)
} else {
newchildren.push(newkid)
}
}
//if to be removed, return a list of children
// if (element.tagName in ["floattext", "table-body", "table-head"]){
if (["FLOATTEXT", "TBODY", "THEAD"].includes(element.tagName)){ // [].includes() not "in []"
return newchildren
} else {
//else add children to self and return self
if (newchildren.length > 0) {
// element.replaceChildren(newchildren)
element.replaceChildren(...newchildren) // Takes individual elements, not an array
}
return element
}
}table {
border: 2px solid red;
}
th {
border: 1px solid black;
padding: 0px 4px;
}
tbody {
background-color: green;
}
thead {
background-color: cyan;
}<button type = "button" onclick = "fancyTableOnClick(event)">Fix Table</button>
<table id = "FancyTableID">
<thead>
<th>sample text</th>
<th>Something</th>
</thead>
<tbody>
<h>Table body</th>
<th>some more sample text</th>
</tbody>
</table>
Всякий раз, когда вы видите
[object Object]или какой-либо другой[object Type], это означает, что ваш код преобразовал объект в строку. напримерlet txt = "x" + obj