Compare commits

...

5 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
6fa98b78b5 Add comprehensive tests for X-Axis configuration fix
Co-authored-by: dfinke <67258+dfinke@users.noreply.github.com>
2025-10-07 16:09:55 +00:00
copilot-swe-agent[bot]
debda51198 Fix X-Axis MajorUnit and MinorUnit for category axes in line charts
Co-authored-by: dfinke <67258+dfinke@users.noreply.github.com>
2025-10-07 16:08:10 +00:00
copilot-swe-agent[bot]
0c1829840d Initial plan 2025-10-07 15:58:05 +00:00
Doug Finke
5387c06146 Merge pull request #1695 from scriptingstudio/master
[Get-HtmlTable] XPath optimization
2025-04-23 08:16:05 -04:00
Matthew Gray
45ed6a06dc [Get-HtmlTable] XPath optimization
```powershell
$rows =    $h.SelectNodes("//table[$TableIndex]//tr")
```
XPath selector in line 53 uses complex expression that can lead to unexpected result. The problem is that HtmlAgilityPack may have specific issues. In particular, on websites containing multiple tables this selector can find not one table. This is aggravated by the fact that tables can have different structures.
To avoid ambiguity this PR suggests to separate queries. Oneliner simplifies error checking
```powershell
$rows = try {
  $h.SelectSingleNode("//table[$TableIndex]").SelectNodes(".//tr")
} catch {}
if (-not $rows) {Write-Warning "Could not find rows for `"//table[$TableIndex]`" in $Url ."}
```
This expression doesn't even need testing, it just works.
2025-04-23 13:36:32 +03:00
3 changed files with 189 additions and 1 deletions

View File

@@ -113,6 +113,57 @@ function Add-ExcelChart {
if ($null -ne $XMinValue) { $chart.XAxis.MinValue = $XMinValue }
if ($null -ne $XMaxValue) { $chart.XAxis.MaxValue = $XMaxValue }
if ($XAxisNumberformat) { $chart.XAxis.Format = (Expand-NumberFormat $XAxisNumberformat) }
# Fix for category axis (used in line charts, etc.): EPPlus doesn't serialize MajorUnit/MinorUnit to XML for category axes
# We need to manually add these elements to the XML if they were specified
if ($XMajorUnit -or $XMinorUnit) {
$chartXml = $chart.ChartXml
$nsManager = New-Object System.Xml.XmlNamespaceManager($chartXml.NameTable)
$null = $nsManager.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$catAx = $chartXml.SelectSingleNode("//c:catAx", $nsManager)
if ($catAx) {
# Category axis exists - need to add majorUnit/minorUnit elements
if ($XMajorUnit) {
$existingMajorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsManager)
if (-not $existingMajorUnit) {
$majorUnitElement = $chartXml.CreateElement("c", "majorUnit", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$null = $majorUnitElement.SetAttribute("val", $XMajorUnit)
# Insert after scaling element or at the beginning
$scalingNode = $catAx.SelectSingleNode("c:scaling", $nsManager)
if ($scalingNode) {
$null = $catAx.InsertAfter($majorUnitElement, $scalingNode)
} else {
$null = $catAx.PrependChild($majorUnitElement)
}
} else {
$null = $existingMajorUnit.SetAttribute("val", $XMajorUnit)
}
}
if ($XMinorUnit) {
$existingMinorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsManager)
if (-not $existingMinorUnit) {
$minorUnitElement = $chartXml.CreateElement("c", "minorUnit", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$null = $minorUnitElement.SetAttribute("val", $XMinorUnit)
# Insert after majorUnit if it exists, otherwise after scaling
$majorUnitNode = $catAx.SelectSingleNode("c:majorUnit", $nsManager)
if ($majorUnitNode) {
$null = $catAx.InsertAfter($minorUnitElement, $majorUnitNode)
} else {
$scalingNode = $catAx.SelectSingleNode("c:scaling", $nsManager)
if ($scalingNode) {
$null = $catAx.InsertAfter($minorUnitElement, $scalingNode)
} else {
$null = $catAx.PrependChild($minorUnitElement)
}
}
} else {
$null = $existingMinorUnit.SetAttribute("val", $XMinorUnit)
}
}
}
}
if ($YAxisTitleText) {
$chart.YAxis.Title.Text = $YAxisTitleText

View File

@@ -50,7 +50,9 @@ function Get-HtmlTable {
else {
$h = ConvertFrom-Html -Content $r.Content
if ($TableIndex -is [valuetype]) { $TableIndex += 1}
$rows = $h.SelectNodes("//table[$TableIndex]//tr")
$rows = try {
$h.SelectSingleNode("//table[$TableIndex]").SelectNodes(".//tr")
} catch {}
if (-not $rows) {Write-Warning "Could not find rows for `"//table[$TableIndex]`" in $Url ."}
if ( -not $propertyNames) {
if ( $tableHeaders = $rows[$FirstDataRow].SelectNodes("th")) {

View File

@@ -0,0 +1,135 @@
# Test for X-Axis configuration on line charts
# This test verifies that XMajorUnit and XMinorUnit parameters work correctly for line charts
Describe "X-Axis Configuration for Line Charts" {
BeforeAll {
$path = "TestDrive:\xaxis_test.xlsx"
}
Context "X-Axis MajorUnit and MinorUnit on Line Charts" {
BeforeAll {
# Create test data
$excel = 1..7 | ForEach-Object {
[pscustomobject][ordered]@{
XValue = @(5, 10, 15, 20, 25, 30, 35)[$_ - 1]
YValue = @(18, 11, 23, 17, 12, 32, 12)[$_ - 1]
}
} | Export-Excel -Path $path -WorksheetName "Test" -PassThru -AutoNameRange
# Add chart with X-axis configuration
Add-ExcelChart -Worksheet $excel.Workbook.Worksheets["Test"] `
-ChartType Line `
-XRange "XValue" `
-YRange "YValue" `
-Title "Test Chart" `
-XMinValue 0 `
-XMaxValue 40 `
-XMajorUnit 10 `
-XMinorUnit 5 `
-YMinValue 0 `
-YMaxValue 40 `
-YMajorUnit 10 `
-YMinorUnit 5
Close-ExcelPackage $excel
# Reopen to verify
$excel = Open-ExcelPackage -Path $path
$ws = $excel.Workbook.Worksheets["Test"]
$chart = $ws.Drawings[0]
}
It "Set XAxis.MinValue correctly" {
$chart.XAxis.MinValue | Should -Be 0
}
It "Set XAxis.MaxValue correctly" {
$chart.XAxis.MaxValue | Should -Be 40
}
It "Set XAxis.MajorUnit correctly" {
$chart.XAxis.MajorUnit | Should -Be 10
}
It "Set XAxis.MinorUnit correctly" {
$chart.XAxis.MinorUnit | Should -Be 5
}
It "Added MajorUnit to category axis XML" {
$xml = $chart.ChartXml
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
$majorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsmgr)
$majorUnit | Should -Not -BeNullOrEmpty
$majorUnit.val | Should -Be "10"
}
It "Added MinorUnit to category axis XML" {
$xml = $chart.ChartXml
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
$minorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsmgr)
$minorUnit | Should -Not -BeNullOrEmpty
$minorUnit.val | Should -Be "5"
}
AfterAll {
Close-ExcelPackage $excel -NoSave
}
}
Context "X-Axis without MajorUnit and MinorUnit" {
BeforeAll {
$path2 = "TestDrive:\xaxis_test2.xlsx"
# Create test data without X-axis units
$excel2 = 1..7 | ForEach-Object {
[pscustomobject][ordered]@{
XValue = @(5, 10, 15, 20, 25, 30, 35)[$_ - 1]
YValue = @(18, 11, 23, 17, 12, 32, 12)[$_ - 1]
}
} | Export-Excel -Path $path2 -WorksheetName "Test" -PassThru -AutoNameRange
# Add chart WITHOUT X-axis MajorUnit/MinorUnit
Add-ExcelChart -Worksheet $excel2.Workbook.Worksheets["Test"] `
-ChartType Line `
-XRange "XValue" `
-YRange "YValue" `
-Title "Test Chart"
Close-ExcelPackage $excel2
# Reopen to verify
$excel2 = Open-ExcelPackage -Path $path2
$ws2 = $excel2.Workbook.Worksheets["Test"]
$chart2 = $ws2.Drawings[0]
}
It "Should not add MajorUnit to category axis XML when not specified" {
$xml = $chart2.ChartXml
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
$majorUnit = $catAx.SelectSingleNode("c:majorUnit", $nsmgr)
$majorUnit | Should -BeNullOrEmpty
}
It "Should not add MinorUnit to category axis XML when not specified" {
$xml = $chart2.ChartXml
$nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$nsmgr.AddNamespace("c", "http://schemas.openxmlformats.org/drawingml/2006/chart")
$catAx = $xml.SelectSingleNode("//c:catAx", $nsmgr)
$minorUnit = $catAx.SelectSingleNode("c:minorUnit", $nsmgr)
$minorUnit | Should -BeNullOrEmpty
}
AfterAll {
Close-ExcelPackage $excel2 -NoSave
}
}
}