Skip to content

Commit

Permalink
Merge pull request #69 from laws-africa/fix-tables
Browse files Browse the repository at this point in the history
Fix tables
  • Loading branch information
goose-life authored Aug 19, 2024
2 parents 2aedec9 + 9b7bc68 commit 2568fd1
Show file tree
Hide file tree
Showing 6 changed files with 2,359 additions and 3 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lawsafrica/indigo-akn",
"version": "5.5.0",
"version": "5.6.0",
"description": "Akoma Ntoso support libraries for the Indigo platform.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/grammars.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { htmlToAkn } from "./html";
import { fixTables } from "./xml";

/**
* Base class for grammar models.
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './html';
export * from './eids';
export * from './enrichments';
export * from './ranges';
export * from './xml';
119 changes: 119 additions & 0 deletions src/xml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* Returns a map of a table, taking all colspans and rowspans into account.
*/
export function mapTable(table) {
let matrix = {},
rows = table.children;

for (let y = 0; y < rows.length; y++) {
// set default
if (!matrix[y]) {
matrix[y] = {};
}
let row = rows[y];
let cells = row.children;
for (let x = 0; x < cells.length; x++) {
// stash 'x' so we don't end the loop prematurely if it's incremented below
let xPos = x;
let cell = cells[x];
// set default; increment xPos if needed (skip already occupied cells in current row)
while (matrix[y][xPos]) {
xPos += 1;
}
matrix[y][xPos] = {};
// mark matrix elements occupied by current cell with true
let colSpanTotal = xPos + Number(cell.getAttribute('colspan') || 1);
let rowSpanTotal = y + Number(cell.getAttribute('rowspan') || 1);

for (let xx = xPos; xx < colSpanTotal; xx++) {
for (let yy = y; yy < rowSpanTotal; yy++) {
if (!matrix[yy]) {
matrix[yy] = {};
}
// don't try to make overlapping spans work
if (matrix[yy][xx] === true) {
throw "Cannot parse overlapping spans in table with eId " + table.getAttribute("eId");
}
matrix[yy][xx] = true;
}
}
}
}
return matrix;
}

/**
* Fixes a table by inserting missing rows and cells to match the table's matrix.
*/
export function fixTable(table) {
// track the fixes
let removedRow = false,
addedRow = false,
addedCell = false;
// remove empty rows before starting
for (let r = 0; r < table.children.length; r++) {
let row = table.children[r];
if (!row.children.length) {
table.removeChild(row);
removedRow = true;
}
}

let xmlns = table.namespaceURI,
tableMap = mapTable(table),
nMappedRows = Object.keys(tableMap).length;

// add missing rows
let nMissingRows = nMappedRows - table.children.length;
for (let y = 0; y < nMissingRows; y++) {
console.log("adding a missing row to table ", table.getAttribute('eId'));
table.appendChild(document.createElementNS(xmlns, 'tr'));
addedRow = true;
}

// add missing cells
let nMaxMappedColumns = Math.max(...Object.values(tableMap).map(r => Object.keys(r).length));
for (let r = 0; r < table.children.length; r++) {
let nMissingCells = nMaxMappedColumns - Object.keys(tableMap[r]).length,
row = table.children[r];
for (let m = 0; m < nMissingCells; m++) {
console.log("adding a missing cell to table ", table.getAttribute('eId'), " row ", r);
let cell = document.createElementNS(xmlns, 'td');
cell.appendChild(document.createElementNS(xmlns, 'p'));
row.appendChild(cell);
addedCell = true;
}
}

// report fixes
if (removedRow || addedRow || addedCell) {
let fixes = [];
if (removedRow) {
fixes.push("removed empty row(s)");
}
if (addedRow) {
fixes.push("added missing row(s)");
}
if (addedCell) {
fixes.push("added missing cell(s)");
}
return `Table with eId ${table.getAttribute('eId')}: ${fixes.join(", ")}`;
} else {
return null;
}
}

/**
* Fixes all tables in a list of Akoma Ntoso XML elements.
*/
export function fixTables (elementList) {
let fixedTables = [];
for (let i = 0; i < elementList.length; i++) {
let tableList = elementList[i].querySelectorAll("table");
for (let t = 0; t < tableList.length; t++) {
let fixed = fixTable(tableList[t]);
if (fixed) {fixedTables.push(fixed);}
}
}
return fixedTables;
}
Loading

0 comments on commit 2568fd1

Please sign in to comment.