Add populate_tablebox.ps1 template + SKILL.md Step 6b (AddField pattern)
This commit is contained in:
parent
a3cb35f078
commit
753a9bd80b
2 changed files with 127 additions and 0 deletions
30
SKILL.md
30
SKILL.md
|
|
@ -109,6 +109,36 @@ Use the template `templates/Reload_wrapped.bat`. Substitute:
|
||||||
Warn user: all `git commit` commands use `--allow-empty` so they never
|
Warn user: all `git commit` commands use `--allow-empty` so they never
|
||||||
fail even when nothing changed.
|
fail even when nothing changed.
|
||||||
|
|
||||||
|
## Step 6b: Populating tableboxes programmatically
|
||||||
|
|
||||||
|
QlikView's COM `TableBoxProperties.Fields.Add()` is BROKEN on modern QV
|
||||||
|
(returns "null-valued expression"). The working pattern is
|
||||||
|
`$tableBox.AddField($fieldName)` — called directly on the SheetObject, NOT on
|
||||||
|
its properties. Use template `templates/populate_tablebox.ps1`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -File populate_tablebox.ps1 `
|
||||||
|
-QvwPath "C:\path\to\app.qvw" `
|
||||||
|
-SheetName "Cash Flow" `
|
||||||
|
-Fields @("%ProdPODateKey","cf_category","cf_payment_date","cf_amount_ron")
|
||||||
|
```
|
||||||
|
|
||||||
|
The script creates the sheet if missing (case-insensitive substring match on
|
||||||
|
name), creates a fresh TableBox on it, and calls AddField per entry.
|
||||||
|
Fields that don't exist in the data model fail silently — pass
|
||||||
|
`-ReplaceExisting $true` to purge existing TBs on the sheet first (removes
|
||||||
|
duplicates when re-running with corrected field lists).
|
||||||
|
|
||||||
|
Common gotchas:
|
||||||
|
- Field must exist in a RESIDENT table at save time. `Dim*` / `Fact*` tables
|
||||||
|
often get dropped in a final-schema-reduction step — their fields won't
|
||||||
|
populate. Check the `1700.ExportCSV.qvs`-style DROP list.
|
||||||
|
- `%CompoundKey`-style field names (`%ProdPODateKey`, `%SupplierPOKey`) work
|
||||||
|
fine — the `%` prefix is literal.
|
||||||
|
- For Dim-only fields that DO survive (e.g. after renaming a drop list),
|
||||||
|
run the `qvw-extract-script` skill first to audit what's actually in the
|
||||||
|
final QVW schema.
|
||||||
|
|
||||||
## Step 7: Changing the script include path (if needed)
|
## Step 7: Changing the script include path (if needed)
|
||||||
|
|
||||||
If the QVW's embedded script points at an old `9.QVSvN` folder and needs
|
If the QVW's embedded script points at an old `9.QVSvN` folder and needs
|
||||||
|
|
|
||||||
97
templates/populate_tablebox.ps1
Normal file
97
templates/populate_tablebox.ps1
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
# populate_tablebox.ps1 — create a new sheet with a populated TableBox on a QVW.
|
||||||
|
#
|
||||||
|
# IMPORTANT: use TableBox.AddField($fieldName) — NOT TableBoxProperties.Fields.Add()
|
||||||
|
# (which fails on modern QV Document COM with "null-valued expression").
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# powershell -File populate_tablebox.ps1 `
|
||||||
|
# -QvwPath "C:\path\to\app.qvw" `
|
||||||
|
# -SheetName "Cash Flow (v9)" `
|
||||||
|
# -Fields @("%ProdPODateKey","cf_category","cf_payment_date","cf_amount_ron","ext_supplier_code")
|
||||||
|
#
|
||||||
|
# The sheet is CREATED if it doesn't match `$SheetName` (case-insensitive substring).
|
||||||
|
# A fresh TableBox is always created on the sheet. Existing TBs are NOT deleted —
|
||||||
|
# pass -ReplaceExisting $true to remove old TBs on the sheet first.
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$QvwPath,
|
||||||
|
[Parameter(Mandatory=$true)][string]$SheetName,
|
||||||
|
[Parameter(Mandatory=$true)][string[]]$Fields,
|
||||||
|
[bool]$ReplaceExisting = $false
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
if (-not (Test-Path $QvwPath)) { throw "QVW not found: $QvwPath" }
|
||||||
|
|
||||||
|
$qv = New-Object -ComObject QlikTech.QlikView
|
||||||
|
$doc = $qv.OpenDoc($QvwPath, "", "")
|
||||||
|
if (-not $doc) { throw "OpenDoc returned null for $QvwPath" }
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
|
||||||
|
# Find or create the sheet
|
||||||
|
$targetSheet = $null
|
||||||
|
$targetSheetId = $null
|
||||||
|
for ($i=0; $i -lt $doc.NoOfSheets(); $i++) {
|
||||||
|
$s = $doc.GetSheet($i)
|
||||||
|
$sp = $s.GetProperties()
|
||||||
|
$nm = $null
|
||||||
|
try { $nm = $sp.Name } catch { try { $nm = $sp.Name.v } catch {} }
|
||||||
|
if ($nm -and ($nm -like "*$SheetName*" -or $nm -eq $SheetName)) {
|
||||||
|
$targetSheet = $s
|
||||||
|
$targetSheetId = $sp.SheetId
|
||||||
|
Write-Host "sheet exists: $nm (id=$targetSheetId)"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $targetSheet) {
|
||||||
|
$targetSheet = $doc.CreateSheet()
|
||||||
|
$sp = $targetSheet.GetProperties()
|
||||||
|
try { $sp.Name = $SheetName } catch { try { $sp.Name.v = $SheetName } catch {} }
|
||||||
|
$targetSheet.SetProperties($sp)
|
||||||
|
$targetSheetId = $targetSheet.GetProperties().SheetId
|
||||||
|
Write-Host "sheet created: $SheetName (id=$targetSheetId)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optionally remove existing TBs on the sheet (reads -prj XML to find them)
|
||||||
|
if ($ReplaceExisting) {
|
||||||
|
$prjPath = [System.IO.Path]::GetDirectoryName($QvwPath) + "\" + [System.IO.Path]::GetFileNameWithoutExtension($QvwPath) + "-prj"
|
||||||
|
$prjXml = Join-Path $prjPath "QlikViewProject.xml"
|
||||||
|
if (Test-Path $prjXml) {
|
||||||
|
$xml = [xml](Get-Content $prjXml)
|
||||||
|
$sheetNode = $xml.PrjQlikViewProject.SHEETS.PrjSheetProperties | Where-Object { $_.SheetId -eq "Document\$targetSheetId" }
|
||||||
|
if ($sheetNode) {
|
||||||
|
foreach ($ch in $sheetNode.ChildObjects.PrjFrameParentDef) {
|
||||||
|
if ($ch.ObjectId -like "Document\TB*") {
|
||||||
|
$tbId = $ch.ObjectId.Replace("Document\","")
|
||||||
|
try {
|
||||||
|
$tb = $doc.GetSheetObject("Document\$tbId")
|
||||||
|
if ($tb) { $tb.Close() | Out-Null; Write-Host " - removed $tbId" }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create fresh tablebox
|
||||||
|
$tb = $targetSheet.CreateTableBox()
|
||||||
|
Start-Sleep -Milliseconds 400
|
||||||
|
|
||||||
|
# Populate via AddField (THIS is the working pattern)
|
||||||
|
$added = 0; $failed = @()
|
||||||
|
foreach ($f in $Fields) {
|
||||||
|
try {
|
||||||
|
$tb.AddField($f) | Out-Null
|
||||||
|
$added++
|
||||||
|
} catch {
|
||||||
|
$failed += $f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write-Host "populated $added/$($Fields.Count) fields"
|
||||||
|
if ($failed.Count) { Write-Host "missed: $($failed -join ', ')" }
|
||||||
|
|
||||||
|
$doc.Save()
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
$doc.CloseDoc()
|
||||||
|
$qv.Quit()
|
||||||
|
Write-Host "DONE"
|
||||||
Loading…
Reference in a new issue