garrmark
garrmark

Reputation: 89

Using PowerShell Core ConvertFrom-Markdown to parse values in a markdown table

I'm interested in using the ConvertFrom-Markdown cmdlet to parse values in a markdown table. The cmdlet uses the markdig markdown processor, which has an Abstract Syntax Tree that should be able to be traversed for this purpose.

How can we search/enumerate the Tokens in the following powershell snippet to return the rows and columns?

(@'
# header1
## header2
| Column1 | Column2 |
| ------- | ------- |
| Row1Column1 | Row1Column2 |
| Row2Column1 | Ro2Column2 |
'@ | ConvertFrom-Markdown).Tokens

The values that I see in the Tokens look promising, I can see Markdig.Extensions.Tables.TableCell in the Parent fields, but that's about as far as I can get.

Upvotes: 1

Views: 1097

Answers (3)

Santiago Squarzon
Santiago Squarzon

Reputation: 61083

They have a MarkdownObjectExtensions.Descendants extension method that can be used to filter, unfortunately extension methods don't translate nicely to PowerShell. This is how you could convert that Markdown table to an array of PowerShell objects using this method:

using namespace Markdig.Syntax
using namespace Markdig.Extensions.Tables

$md = @'
# header1
## header2
| Column1 | Column2 |
| ------- | ------- |
| Row1Column1 | Row1Column2 |
| Row2Column1 | Ro2Column2 |
'@ | ConvertFrom-Markdown

foreach ($table in [MarkdownObjectExtensions]::Descendants[Table]($md.Tokens)) {
    foreach ($row in [MarkdownObjectExtensions]::Descendants[TableRow]($table)) {
        if ($row.IsHeader) {
            $headers = foreach ($header in [MarkdownObjectExtensions]::Descendants[TableCell]($row)) {
                $header.Inline.Content.ToString()
            }
            continue
        }

        $tmp = [ordered]@{}; $idx = 0
        foreach ($cell in [MarkdownObjectExtensions]::Descendants[TableCell]($row)) {
            $tmp[$headers[$idx++]] = $cell.Inline.Content.ToString()
        }
        [pscustomobject] $tmp
    }
}

It would result in:

Column1     Column2
-------     -------
Row1Column1 Row1Column2
Row2Column1 Ro2Column2

Upvotes: 0

Dennis
Dennis

Reputation: 1800

If you like to import the markdown tables into PowerShell arrays, you can parse and build PsCustomObjects as well along the way...

$MarkDown = @"
# header1
## header2
| Column1 | Column2 |
| ------- | ------- |
| Row1Column1 | Row1Column2 |
| Row2Column1 | Ro2Column2 |

| Table2 Column1 |
| ------------- |
| T2 Row1 |
| T2 Row2 |
| T2 Row3 |
"@ | ConvertFrom-Markdown

$mdDoc = $Markdown.Tokens
[array]$tables = $null
$mdTables = @($mdDoc | where {$_ -is [Markdig.Extensions.Tables.Table]})

foreach ($mdTable in $mdTables) {
    [array]$table = $null
    $mdRows = @($mdTable | where {$_ -is [Markdig.Extensions.Tables.TableRow]})

    foreach ($mdRow in $mdRows) {
        $mdCells = @($mdRow | where-object { $_ -is [Markdig.Extensions.Tables.TableCell]})
        $mdCellsValues = @($mdCells.Inline.Content | foreach {$_.ToString()})

        if ($mdRow.IsHeader) {# don't use headers as values
            $CustomProperties = $mdCellsValues
        } else {# iterate throw the customobject and populate it
            $thisrow = New-Object PSCustomObject | select $CustomProperties
            
            foreach ($i in 0..($CustomProperties.Count -1)) {
                $thisrow.($CustomProperties[$i]) = $mdCellsValues[$i]
            }

            $table += $thisrow
        }# endif

    }#end tablerows

    $tables += ,$table #add each table a sub arrays
    
}#end tables

$tables

The result is available in two sub arrays

C:\> $tables[0]

Column1     Column2
-------     -------
Row1Column1 Row1Column2
Row2Column1 Ro2Column2

C:\> $tables[1]

Table2 Column1
-------------
T2 Row1
T2 Row2
T2 Row3

Upvotes: 0

mclayton
mclayton

Reputation: 10095

Here's a way to do it.

Note I'm not sure if, example a Table can contain only TableRows, so the | where-object { ... } might not be necessary.

# set up some sample data
$md = @"
# header1
## header2
| Column1 | Column2 |
| ------- | ------- |
| Row1Column1 | Row1Column2 |
| Row2Column1 | Ro2Column2 |
"@ | ConvertFrom-Markdown

# walk the syntax tree
$mdDoc = $md.Tokens;
$mdTables = @( $mdDoc | where-object { $_ -is [Markdig.Extensions.Tables.Table] } ); 
foreach( $mdTable in $mdTables )
{
    write-host "table";
    $mdRows = @( $mdTable | where-object { $_ -is [Markdig.Extensions.Tables.TableRow] } );
    foreach( $mdRow in $mdRows )
    {
        write-host "  row";
        write-host "    header = $($mdRow.IsHeader)";
        $mdCells = @( $mdRow | where-object { $_ -is [Markdig.Extensions.Tables.TableCell] } );
        foreach( $mdCell in $mdCells )
        {
            write-host "    cell";
            $mdInline = $mdCell.Inline;
            write-host "      inline - $($mdInline.Content)";
        }
    }
}

Which gives the following output:

table
  row
    header = True
    cell
      inline - Column1
    cell
      inline - Column2
  row
    header = False
    cell
      inline - Row1Column1
    cell
      inline - Row1Column2
  row
    header = False
    cell
      inline - Row2Column1
    cell
      inline - Ro2Column2

Hopefully that'll be enough to get you started...

Upvotes: 3

Related Questions