Skip to content

Commit

Permalink
Merge pull request #713 from dfinke/FixImportExcelHeaders
Browse files Browse the repository at this point in the history
Fix import excel headers
  • Loading branch information
dfinke authored Nov 10, 2019
2 parents 321699e + ef6defd commit 5959a97
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 15 deletions.
32 changes: 17 additions & 15 deletions ImportExcel.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ if (($IsLinux -or $IsMacOS) -or $env:NoAutoSize) {
$Cells.Value = 'Test'
try {
$Cells.AutoFitColumns()
if ($env:NoAutoSize) {Remove-Item Env:\NoAutoSize}
if ($env:NoAutoSize) { Remove-Item Env:\NoAutoSize }
}
catch {
$env:NoAutoSize = $true
if ($IsLinux) {
Write-Warning -Message ('ImportExcel Module Cannot Autosize. Please run the following command to install dependencies:' + [environment]::newline +
'"sudo apt-get install -y --no-install-recommends libgdiplus libc6-dev"')
'"sudo apt-get install -y --no-install-recommends libgdiplus libc6-dev"')
}
if ($IsMacOS) {
Write-Warning -Message ('ImportExcel Module Cannot Autosize. Please run the following command to install dependencies:' + [environment]::newline +
'"brew install mono-libgdiplus"')
'"brew install mono-libgdiplus"')
}
}
finally {
Expand Down Expand Up @@ -342,20 +342,21 @@ function Import-Excel {
)

Try {
if ($NoHeader) {
if ($HeaderName) {
$i = 0
foreach ($C in $Columns) {
foreach ($H in $HeaderName) {
$H | Select-Object @{N = 'Column'; E = { $Columns[$i] } }, @{N = 'Value'; E = { $H } }
$i++
$C | Select-Object @{N = 'Column'; E = { $_ } }, @{N = 'Value'; E = { 'P' + $i } }
}
}
elseif ($HeaderName) {
elseif ($NoHeader) {
$i = 0
foreach ($H in $HeaderName) {
$H | Select-Object @{N = 'Column'; E = { $Columns[$i] } }, @{N = 'Value'; E = { $H } }
foreach ($C in $Columns) {
$i++
$C | Select-Object @{N = 'Column'; E = { $_ } }, @{N = 'Value'; E = { 'P' + $i } }
}
}

else {
if ($StartRow -lt 1) {
throw 'The top row can never be less than 1 when we need to retrieve headers from the worksheet.' ; return
Expand Down Expand Up @@ -389,8 +390,8 @@ function Import-Excel {

$stream = New-Object -TypeName System.IO.FileStream -ArgumentList $Path, 'Open', 'Read', 'ReadWrite'
$ExcelPackage = New-Object -TypeName OfficeOpenXml.ExcelPackage
if ($Password) { $ExcelPackage.Load($stream,$Password)}
else { $ExcelPackage.Load($stream) }
if ($Password) { $ExcelPackage.Load($stream, $Password) }
else { $ExcelPackage.Load($stream) }
}
try {
#Select worksheet
Expand Down Expand Up @@ -424,6 +425,7 @@ function Import-Excel {
else {
$Columns = $StartColumn .. $EndColumn ; if ($StartColumn -gt $EndColumn) { Write-Warning -Message "Selecting columns $StartColumn to $EndColumn might give odd results." }
if ($NoHeader) { $Rows = $StartRow..$EndRow ; if ($StartRow -gt $EndRow) { Write-Warning -Message "Selecting rows $StartRow to $EndRow might give odd results." } }
elseif ($HeaderName) { $Rows = $StartRow..$EndRow }
else { $Rows = (1 + $StartRow)..$EndRow } # ; if ($StartRow -ge $EndRow) { Write-Warning -Message "Selecting $StartRow as the header with data in $(1+$StartRow) to $EndRow might give odd results." } }
}
#endregion
Expand All @@ -447,7 +449,7 @@ function Import-Excel {
So if we get "Week", "[Time]" and "*date*" ; make the expression ^week$|^\[Time\]$|^.*Date.*$
$make a regex for this which is case insensitive (option 1) and compiled (option 8)
#>
$TextColExpression = "^" + [regex]::Escape($AsText -join "~~~").replace("\*",".*").replace("~~~","$|^") +"$"
$TextColExpression = "^" + [regex]::Escape($AsText -join "~~~").replace("\*", ".*").replace("~~~", "$|^") + "$"
$TextColRegEx = New-Object -TypeName regex -ArgumentList $TextColExpression , 9
}
foreach ($R in $Rows) {
Expand All @@ -457,10 +459,10 @@ function Import-Excel {
if ($TextColRegEx) {
foreach ($P in $PropertyNames) {
if ($TextColRegEx.IsMatch($P.Value)) {
$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text
$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Text
}
else {$NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value}
}
else { $NewRow[$P.Value] = $Worksheet.Cells[$R, $P.Column].Value }
}
}
else {
foreach ($P in $PropertyNames) {
Expand Down
196 changes: 196 additions & 0 deletions __tests__/ImportExcelHeaderName.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
$xlfile = "TestDrive:\testImportExcel.xlsx"

Describe "Import-Excel on a sheet with no headings" {
BeforeAll {

$xl = "" | export-excel $xlfile -PassThru

Set-Format -WorkSheet $xl.Sheet1 -Range A1 -Value 'A'
Set-Format -WorkSheet $xl.Sheet1 -Range B1 -Value 'B'
Set-Format -WorkSheet $xl.Sheet1 -Range C1 -Value 'C'

Set-Format -WorkSheet $xl.Sheet1 -Range A2 -Value 'D'
Set-Format -WorkSheet $xl.Sheet1 -Range B2 -Value 'E'
Set-Format -WorkSheet $xl.Sheet1 -Range C2 -Value 'F'

Set-Format -WorkSheet $xl.Sheet1 -Range A3 -Value 'G'
Set-Format -WorkSheet $xl.Sheet1 -Range B3 -Value 'H'
Set-Format -WorkSheet $xl.Sheet1 -Range C3 -Value 'I'

Close-ExcelPackage $xl
}

It "Import-Excel should have this shape" {
$actual = @(Import-Excel $xlfile)

$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'A'
$actualNames[1] | Should BeExactly 'B'
$actualNames[2] | Should BeExactly 'C'

$actual.Count | Should Be 2
$actual[0].A | Should BeExactly 'D'
$actual[0].B | Should BeExactly 'E'
$actual[0].C | Should BeExactly 'F'
}

It "Import-Excel -NoHeader should have this shape" {
$actual = @(Import-Excel $xlfile -NoHeader)

$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'P1'
$actualNames[1] | Should BeExactly 'P2'
$actualNames[2] | Should BeExactly 'P3'

$actual.Count | Should Be 3
}

It "Import-Excel -HeaderName should have this shape" {
$actual = @(Import-Excel $xlfile -HeaderName 'Q', 'R', 'S')

$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'Q'
$actualNames[1] | Should BeExactly 'R'
$actualNames[2] | Should BeExactly 'S'

$actual.Count | Should Be 3

$actual[0].Q | Should BeExactly 'A'
$actual[0].R | Should BeExactly 'B'
$actual[0].S | Should BeExactly 'C'

$actual[1].Q | Should BeExactly 'D'
$actual[1].R | Should BeExactly 'E'
$actual[1].S | Should BeExactly 'F'
}

It "Should work with StartRow" {
$actual = @(Import-Excel $xlfile -HeaderName 'Q', 'R', 'S' -startrow 2)

$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'Q'
$actualNames[1] | Should BeExactly 'R'
$actualNames[2] | Should BeExactly 'S'

$actual.Count | Should Be 2

$actual[0].Q | Should BeExactly 'D'
$actual[0].R | Should BeExactly 'E'
$actual[0].S | Should BeExactly 'F'

$actual[1].Q | Should BeExactly 'G'
$actual[1].R | Should BeExactly 'H'
$actual[1].S | Should BeExactly 'I'

}

It "Should work with -NoHeader" {
$actual = @(Import-Excel $xlfile -NoHeader)
$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'P1'
$actualNames[1] | Should BeExactly 'P2'
$actualNames[2] | Should BeExactly 'P3'

$actual.Count | Should Be 3

$actual[0].P1 | Should BeExactly 'A'
$actual[0].P2 | Should BeExactly 'B'
$actual[0].P3 | Should BeExactly 'C'

$actual[1].P1 | Should BeExactly 'D'
$actual[1].P2 | Should BeExactly 'E'
$actual[1].P3 | Should BeExactly 'F'

$actual[2].P1 | Should BeExactly 'G'
$actual[2].P2 | Should BeExactly 'H'
$actual[2].P3 | Should BeExactly 'I'
}

It "Should work with -NoHeader -DataOnly" {
$actual = @(Import-Excel $xlfile -NoHeader -DataOnly)
$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'P1'
$actualNames[1] | Should BeExactly 'P2'
$actualNames[2] | Should BeExactly 'P3'

$actual.Count | Should Be 3

$actual[0].P1 | Should BeExactly 'A'
$actual[0].P2 | Should BeExactly 'B'
$actual[0].P3 | Should BeExactly 'C'

$actual[1].P1 | Should BeExactly 'D'
$actual[1].P2 | Should BeExactly 'E'
$actual[1].P3 | Should BeExactly 'F'

$actual[2].P1 | Should BeExactly 'G'
$actual[2].P2 | Should BeExactly 'H'
$actual[2].P3 | Should BeExactly 'I'
}

It "Should work with -HeaderName -DataOnly -StartRow" {
$actual = @(Import-Excel $xlfile -HeaderName 'Q', 'R', 'S' -DataOnly -StartRow 2)
$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'Q'
$actualNames[1] | Should BeExactly 'R'
$actualNames[2] | Should BeExactly 'S'

$actual.Count | Should Be 1

$actual[0].Q | Should BeExactly 'G'
$actual[0].R | Should BeExactly 'H'
$actual[0].S | Should BeExactly 'I'
}

It "Should" {
$xlfile = "TestDrive:\testImportExcelSparse.xlsx"
$xl = "" | export-excel $xlfile -PassThru

Set-Format -WorkSheet $xl.Sheet1 -Range A1 -Value 'Chuck'
Set-Format -WorkSheet $xl.Sheet1 -Range B1 -Value ''
Set-Format -WorkSheet $xl.Sheet1 -Range C1 -Value 'Norris'
Set-Format -WorkSheet $xl.Sheet1 -Range D1 -Value 'California'

Set-Format -WorkSheet $xl.Sheet1 -Range A2 -Value ''
Set-Format -WorkSheet $xl.Sheet1 -Range B2 -Value ''
Set-Format -WorkSheet $xl.Sheet1 -Range C2 -Value ''
Set-Format -WorkSheet $xl.Sheet1 -Range D2 -Value ''

Set-Format -WorkSheet $xl.Sheet1 -Range A3 -Value 'Jean-Claude'
Set-Format -WorkSheet $xl.Sheet1 -Range B3 -Value ''
Set-Format -WorkSheet $xl.Sheet1 -Range C3 -Value 'Vandamme'
Set-Format -WorkSheet $xl.Sheet1 -Range D3 -Value 'Brussels'

Close-ExcelPackage $xl

$actual = @(Import-Excel -Path $xlfile -DataOnly -HeaderName 'FirstName', 'SecondName', 'City' -StartRow 2)
$actualNames = $actual[0].psobject.properties.name

$actualNames.Count | Should Be 3
$actualNames[0] | Should BeExactly 'FirstName'
$actualNames[1] | Should BeExactly 'SecondName'
$actualNames[2] | Should BeExactly 'City'

$actual.Count | Should Be 1

# Looks like -DataOnly does not handle empty columns
# $actual[0].FirstName | Should BeExactly 'Jean-Claude'
# $actual[0].SecondName | Should BeExactly 'Vandamme'
# $actual[0].City | Should BeExactly 'Brussels'
}

}

0 comments on commit 5959a97

Please sign in to comment.