Методика выборочного форматирования данных в конвейере PowerShell и вывода в виде HTML - PullRequest
2 голосов
/ 30 декабря 2010

Скажем, что вы хотите сделать какое-то необычное форматирование табличного вывода из powershell, и назначение должно быть html (либо для веб-сервера, либо для отправки по электронной почте). Скажем, например, что вы хотите, чтобы определенные числовые значения имели другой цвет фона. Без разницы. Я могу придумать два надежных программных способа сделать это: вывести XML и преобразовать с помощью XSLT или вывести HTML и декорировать с помощью CSS.

XSLT, вероятно, сложнее из двух (я говорю это, потому что я этого не знаю), но из того, что я помню, у него есть то преимущество, что он способен встраивать критерии выбора (xpath?) Для вышеупомянутой фантазии. форматирование. CSS, с другой стороны, нуждается в помощи. Если вы хотите, чтобы с определенной ячейкой обращались особым образом, вам нужно было бы отличить ее от братьев и сестер с помощью класса, идентификатора или чего-то подобного. PowerShell на самом деле не имеет способа сделать это изначально, так что это будет означать синтаксический анализ HTML, поскольку он оставляет convertto-html и добавляет, например, класс выделений:

<td class="emphasis">32MB</td>

Мне не нравится идея необходимого синтаксического анализа текста, особенно учитывая, что я предпочел бы как-то подчеркнуть, что нужно выделить в Powershell, прежде чем он попадет в HTML.

Является ли XSLT лучшим способом? Есть предложения о том, как разметить HTML после того, как он оставляет convertto-html или идеи по-другому?

Ответы [ 4 ]

7 голосов
/ 06 января 2011

Эй, я придумал другой ответ, который мне нравится больше.Этот не зависит от браузера, поддерживающего JavaScript ...

Add-Type -AssemblyName System.Xml.Linq

# Get the running processes to x(ht)ml
$xml = [System.Xml.Linq.XDocument]::Parse( "$(Get-Process | ConvertTo-Html)" )

# Find the index of the column you want to format:
$wsIndex = (($xml.Descendants("{http://www.w3.org/1999/xhtml}th") | Where-Object { $_.Value -eq "WS" }).NodesBeforeSelf() | Measure-Object).Count

# Format the column based on whatever rules you have:
switch($xml.Descendants("{http://www.w3.org/1999/xhtml}td") | Where { ($_.NodesBeforeSelf() | Measure).Count -eq $wsIndex } ) {
   {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
   {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
   {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
}
# Save the html out to a file
$xml.Save("$pwd/procs2.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html

Есть ли специальный значок для кражи "помечен как ответ" от вас?; -)

7 голосов
/ 03 января 2011

Как насчет использования JQuery и вставки заголовка со скриптом JQUery и некоторыми стилями, такими как:

Get-Process | ConvertTo-Html -Head @'

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {

   $("table tr td:nth-child(" + ( $("table th:contains('WS')").index() + 1 ) + ")").each(function() {
      if($(this).html() > 209715200) { // 200MB
         $(this).css("background", "red" );
      } else if($(this).html() > 20971520) { // 20MB
         $(this).css("background", "orange" );
      } else if($(this).html() > 10485760) { // 10MB
         $(this).css("background", "yellow" );
      }
   });

})
</script>

'@ | Out-File procs.html; ii .\procs.html
5 голосов
/ 06 января 2011

A намного быстрее:

Хорошо, я продолжаю обещать себе, что больше не буду тратить время на решение проблем, но ... для того, чтобы оператор switch во втором ответе занял в моей системе более 10 секунд, - потому что он выполняет " где "вещи в PowerShell, а не в LINQ.

Поскольку PowerShell не поддерживает LINQ, я решил эту проблему, написав статический вспомогательный метод в вызове Add-Type (и ускорил этот оператор switch примерно в 1000 раз):

Add-Type -Language CSharpVersion3 -ReferencedAssemblies System.Xml, System.Xml.Linq -UsingNamespace System.Linq -Name XUtilities -Namespace Huddled -MemberDefinition @"    
    public static System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement> GetElementByIndex( System.Xml.Linq.XContainer doc, System.Xml.Linq.XName element, int index) {
        return from e in doc.Descendants(element) where e.NodesBeforeSelf().Count() == index select e;
    }
    public static System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement> GetElementByValue( System.Xml.Linq.XContainer doc, System.Xml.Linq.XName element, string value) {
        return from e in doc.Descendants(element) where e.Value == value select e;
    }
"@

# Get the running processes to x(ht)ml
$xml = [System.Xml.Linq.XDocument]::Parse( "$(Get-Process | ConvertTo-Html)" )

# Find the index of the column you want to format:
$wsIndex = [Huddled.XUtilities]::GetElementByValue( $xml, "{http://www.w3.org/1999/xhtml}th", "WS" ) | %{ ($_.NodesBeforeSelf() | Measure).Count }


switch([Huddled.XUtilities]::GetElementByIndex( $xml, "{http://www.w3.org/1999/xhtml}td", $wsIndex )) {
   {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
   {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
   {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
}

# Save the html out to a file
$xml.Save("$pwd/procs2.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html

PowerShell 3:

Я переделал это в PowerShell 3 после того, как кто-то связался с этим постом, и вам больше не нужны скомпилированные типы, чтобы получить его быстро:

Add-Type -AssemblyName System.Xml.Linq

$Process = $(Get-Process | Select Handles, NPM, PM, WS, VM, CPU, Id, ProcessName)

$xml = [System.Xml.Linq.XDocument]::Parse( "$($Process | ConvertTo-Html)" )
if($Namespace = $xml.Root.Attribute("xmlns").Value) {
    $Namespace = "{{{0}}}" -f $Namespace
}

# Find the index of the column you want to format:
$wsIndex = [Array]::IndexOf( $xml.Descendants("${Namespace}th").Value, "WS")

foreach($row in $xml.Descendants("${Namespace}tr")){
    switch(@($row.Descendants("${Namespace}td"))[$wsIndex]) {
       {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
       {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
       {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue } 
    }
}
# Save the html out to a file
$xml.Save("$pwd/procs1.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html
1 голос
/ 30 апреля 2018

В результате некоторых обсуждений на github я обновил это для PowerShell 4/5/6, используя метод .where(), таким образом устраняя зависимость от конвейера.Медленная часть генерирует HTML, тогда как фактические манипуляции с XML занимают всего ~ 200 мс.

Add-Type -AssemblyName System.Xml.Linq

# Get the running processes to x(ht)ml. This is *SLOW*.
$xml = [System.Xml.Linq.XDocument]::Parse([string] (Get-Process | ConvertTo-Html))

# Find the index of the column you want to format:
$wsIndex = $xml.Descendants("{http://www.w3.org/1999/xhtml}th").
    Where{$_.Value -eq "WS" }.
        NodesBeforeSelf().
            Count

# Format the column based on whatever rules you have:
switch($xml.Descendants("{http://www.w3.org/1999/xhtml}td").Where{@($_.NodesBeforeSelf()).Count -eq $wsIndex} ) {
   {200MB -lt $_.Value } { $_.SetAttributeValue( "style", "background: red;"); continue } 
   {20MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: orange;"); continue } 
   {10MB  -lt $_.Value } { $_.SetAttributeValue( "style", "background: yellow;"); continue }
}

# Save the html out to a file
$xml.Save("$pwd/procs2.html")

# Open the thing in your browser to see what we've wrought
ii .\procs2.html
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...