Как я могу добавить новую строку в com HTML-объект powershell

#html #powershell #com

Вопрос:

У меня есть таблица, в которую я пытаюсь добавить больше строк с помощью powershell, а затем экспортировать ее в виде нового HTML-файла.

Вот текст HTML — кода, в который я пытаюсь добавить строки.

 <BODY>
<TABLE style="WIDTH: 100%" cellPadding=5>
<TBODY>
<TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR></TBODY></TABLE>
<TABLE>
<TBODY></TBODY></TABLE></BODY>
 

Я подумал, что мне нужно будет изменить внутренний html-код объекта, но это просто выдает ошибку.
Вот мой код

 $src = [IO.File]::ReadAllText($outPath)

$doc = New-Object -com "HTMLFILE"
$doc.IHTMLDocument2_write($src)

$elm = $doc.getElementsByTagName('tr')[0]
$elm.innerHTML = "<TR>New row!</TR>"
 

Когда я проверяю внутреннюю переменную html, я получаю вывод HTML, который я ожидал бы, поэтому он захватывает правильный объект, но я ничего не могу ему назначить по какой-либо причине.

Вот в чем ошибка

 Exception from HRESULT: 0x800A0258
At line:1 char:1
  $elm.innerHTML = "<TH>User</TH>"
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      CategoryInfo          : OperationStopped: (:) [], COMException
      FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
 

Комментарии:

1. В такой ситуации лучше изменить данные в источнике. Веб-сайт, скорее всего, получает какие-то структурированные данные, а затем преобразуется в html. К вашему сведению, конвертировать в html намного проще, чем из html. Настоятельно рекомендую вам решить эту проблему на другом конце.

Ответ №1:

Вместо изменения innerHTML содержимого существующего <tr> элемента вам потребуется:

  • Создайте новый <tr> элемент
    • Создайте любой необходимый <td> дочерний элемент(ы)
    • Добавьте <td> элемент(ы) в вашу новую строку
  • Добавьте новую строку к существующей <tbody>

Попробуйте что-нибудь вроде этого:

 $html = @'
<BODY>
<TABLE style="WIDTH: 100%" cellPadding=5>
<TBODY>
<TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR></TBODY></TABLE>
<TABLE>
<TBODY></TBODY></TABLE></BODY>
'@

# Create HTML document object
$doc = New-Object -ComObject HTMLFile

# Load existing HTML
$doc.IHTMLDocument2_write($html)

# Create new row element
$newRow = $doc.createElement('tr')

# Create new cell element
$newCell = $doc.createElement('td')
$newCell.innerHTML = "New row!"
$newCell.colSpan = 5

# Append cell to row
$newRow.appendChild($newCell)

# Append row to table body
$tbody = $doc.getElementsByTagName('tbody')[0]
$tbody.appendChild($newRow)

# Inspect resulting HTML
$tbody.outerHtml
 

Вы должны ожидать, что новая строка будет добавлена в текст таблицы:

 <TBODY><TR>
<TH>Bruger</TH>
<TH>Windows</TH>
<TH>Installations dato</TH>
<TH>Model</TH>
<TH>Sidst slukket</TH></TR>
<TR>
<TD>Users name</TD>
<TD>Windows 10 Pro</TD>
<TD>23-01-2020</TD>
<TD>ThinkPad</TD>
<TD>7 dage</TD></TR>
<TR>
<TD colSpan=5>New row!</TD></TR></TBODY>
 

Вы могли бы создать небольшую приятную вспомогательную функцию для добавления новых строк:

 function New-HTMLFileTableRow {
  param(
    [Parameter(Mandatory)]
    [mshtml.HTMLDocumentClass]$Document,
    
    [Parameter(Mandatory)]
    [string[]]$Property,

    [Parameter(Mandatory, ValueFromPipeline)]
    $InputObject
  )

  process {
    $newRow = $Document.createElement('tr')
    foreach($propName in $Property){
      $newCell = $Document.createElement('td')
      $newCell.innerHtml = $InputObject.$propName
      [void]$newRow.appendChild($newCell)
    }

    return $newRow
  }
}
 

Затем используйте как:

 Import-Csv .pathtouser-os-list.csv |New-HTMLFileTableRow -Property User,OSVersion,InstallDate,Model,LastActive -Document $doc |ForEach-Object {
  [void]$tbody.appendChild($_)
}
 

Комментарии:

1. Это сработало прекрасно, спасибо! Однако один вопрос: как я могу удалить строку?

2. @Baxorr Добро пожаловать! Для удаления узлов/элементов найдите родительский элемент и удалите дочерний узел, например. $row1 = $doc.getElementsByTagName('tr')[1]; [void]$row1.parentElement.removeChild($row1)

3. Чувак, ты потрясающий! Я нигде не мог найти никакой документации по этому поводу

4. @Baxorr вот в чем хитрость: HTML DOM по сути является живым XML-документом, поэтому я просто использую тот же подход, что и при редактировании xml 🙂