feat: dix all pdf problems. Validator now green
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
GOARCH=amd64 GOOS=windows go build -ldflags "-s -w" -o dist/pdf_xml_helper.exe main.go
|
GOARCH=amd64 GOOS=windows go build -ldflags "-s -w" -o dist/pdf_xml_helper.exe main.go
|
||||||
|
go build -ldflags "-s -w" -o dist/pdf_xml_helper main.go
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
2026-02-07 16:24:43 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 16:24:43 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 16:27:07 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 16:27:07 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 16:31:28 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 16:31:28 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 16:31:28 leave appendToPdf
|
||||||
|
2026-02-07 16:46:56 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 16:46:56 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 16:46:56 leave appendToPdf
|
||||||
|
2026-02-07 17:00:03 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:00:03 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:02:58 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:02:58 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:03:39 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:03:39 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:05:24 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:05:24 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:05:59 leave appendToPdf
|
||||||
|
2026-02-07 17:08:43 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:08:43 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:11:09 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:11:09 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:12:31 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:12:31 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:13:34 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:13:34 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:13:34 leave appendToPdf
|
||||||
|
2026-02-07 17:13:38 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:13:38 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:15:13 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:15:13 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:16:18 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:16:18 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:19:00 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:19:00 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:21:06 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:21:06 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:23:32 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:23:32 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-07 17:31:00 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-07 17:31:00 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:14:12 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:14:12 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:14:12 leave appendToPdf
|
||||||
|
2026-02-08 10:15:48 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:15:48 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:17:46 leave appendToPdf
|
||||||
|
2026-02-08 10:17:47 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:17:47 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:17:47 leave appendToPdf
|
||||||
|
2026-02-08 10:18:38 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:18:38 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:18:38 leave appendToPdf
|
||||||
|
2026-02-08 10:19:18 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:19:18 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:19:18 leave appendToPdf
|
||||||
|
2026-02-08 10:22:04 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:22:04 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:22:07 leave appendToPdf
|
||||||
|
2026-02-08 10:22:16 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:22:16 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:24:22 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:24:22 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:27:57 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:27:57 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:34:06 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:34:06 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:37:06 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:37:06 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:39:06 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:39:06 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:41:13 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:41:13 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:45:58 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:45:58 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:45:58 leave appendToPdf
|
||||||
|
2026-02-08 10:46:10 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:46:10 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:46:10 leave appendToPdf
|
||||||
|
2026-02-08 10:46:45 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:46:45 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:46:45 leave appendToPdf
|
||||||
|
2026-02-08 10:48:01 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:48:01 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:53:16 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:53:16 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:53:16 leave appendToPdf
|
||||||
|
2026-02-08 10:59:53 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 10:59:53 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 10:59:59 leave appendToPdf
|
||||||
|
2026-02-08 11:03:20 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:03:20 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:03:20 leave appendToPdf
|
||||||
|
2026-02-08 11:04:16 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:04:16 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:06:12 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:06:12 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:06:12 leave appendToPdf
|
||||||
|
2026-02-08 11:06:43 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:06:43 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:06:43 leave appendToPdf
|
||||||
|
2026-02-08 11:09:57 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:09:57 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:12:28 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:12:28 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:12:36 leave appendToPdf
|
||||||
|
2026-02-08 11:14:15 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:14:15 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:14:15 leave appendToPdf
|
||||||
|
2026-02-08 11:17:27 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:17:27 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:17:27 leave appendToPdf
|
||||||
|
2026-02-08 11:18:57 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:18:57 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:18:57 leave appendToPdf
|
||||||
|
2026-02-08 11:19:25 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:19:25 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:19:25 leave appendToPdf
|
||||||
|
2026-02-08 11:23:48 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:23:48 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:23:48 leave appendToPdf
|
||||||
|
2026-02-08 11:24:14 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:24:14 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:24:14 leave appendToPdf
|
||||||
|
2026-02-08 11:26:19 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 11:26:19 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 11:30:08 leave appendToPdf
|
||||||
|
2026-02-08 12:30:30 enter ExtractFromPdf(./testdata/EN16931_Physiotherapeut_fx.pdf, )
|
||||||
|
2026-02-08 12:30:30 pdfInput: './testdata/EN16931_Physiotherapeut_fx.pdf' output: './testdata/EN16931_Physiotherapeut_fx.xml'
|
||||||
|
2026-02-08 12:30:30 {factur-x.xml Factur-X Rechnung text/xml 13768 4151 0001-01-01 00:00:00 +0000 UTC 2025-12-03 21:24:56 +0000 +0000 [48 97 48 53 57 56 101 49 102 48 49 52 101 48 51 51 51 54 52 53 50 98 101 100 57 53 97 50 51 55 97 101] Alternative false 29 0 R 28 0 R}
|
||||||
|
2026-02-08 12:31:13 leave extractFromPdf
|
||||||
|
2026-02-08 12:31:31 enter ExtractFromPdf(./tmp/test.pdf, )
|
||||||
|
2026-02-08 12:31:31 pdfInput: './tmp/test.pdf' output: './tmp/test.xml'
|
||||||
|
2026-02-08 12:31:31 {factur-x.xml Rechnung text/xml 15891 2371 0001-01-01 00:00:00 +0000 UTC 2026-02-08 11:26:25 +0100 +0100 [104 87 4 121 245 4 124 6 192 221 18 52 191 180 47 37] Alternative false 32 0 R 31 0 R}
|
||||||
|
2026-02-08 12:35:42 leave extractFromPdf
|
||||||
|
2026-02-08 12:35:54 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 12:35:54 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:00:39 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:00:39 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:00:39 leave appendToPdf
|
||||||
|
2026-02-08 13:03:25 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:03:25 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:03:25 leave appendToPdf
|
||||||
|
2026-02-08 13:04:09 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:04:09 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:04:26 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:04:26 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:06:12 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:06:12 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:06:12 leave appendToPdf
|
||||||
|
2026-02-08 13:11:18 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test.pdf)
|
||||||
|
2026-02-08 13:11:18 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test.pdf'
|
||||||
|
2026-02-08 13:11:18 leave appendToPdf
|
||||||
|
2026-02-08 13:14:54 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test_1.pdf)
|
||||||
|
2026-02-08 13:14:54 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test_1.pdf'
|
||||||
|
2026-02-08 13:14:54 leave appendToPdf
|
||||||
|
2026-02-08 13:26:55 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test_1.pdf)
|
||||||
|
2026-02-08 13:26:55 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test_1.pdf'
|
||||||
|
2026-02-08 13:26:55 leave appendToPdf
|
||||||
|
2026-02-08 13:29:56 enter appendToPdf(./testdata/180274_20250915_Rechnung-32096.PDF, ./testdata/180274_20250915_Rechnung-32096.xml, tmp/test_1.pdf)
|
||||||
|
2026-02-08 13:29:56 pdfInput: './testdata/180274_20250915_Rechnung-32096.PDF' xmlInput: './testdata/180274_20250915_Rechnung-32096.xml' output: 'tmp/test_1.pdf'
|
||||||
|
2026-02-08 13:29:56 leave appendToPdf
|
||||||
|
|||||||
+4
-3
@@ -70,12 +70,13 @@ func AppendToPdf(
|
|||||||
defer inputFile.Close()
|
defer inputFile.Close()
|
||||||
|
|
||||||
var result io.Reader
|
var result io.Reader
|
||||||
result, err = addAttachment(inputFile, inputXmlFilePath, embedName, description)
|
|
||||||
|
result, err = addXmpData(inputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err = addXmpData(result)
|
result, err = addAttachment(result, inputXmlFilePath, embedName, description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,7 @@ func addAttachment(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = doc.AddAttachment(attachment.Attachment{
|
err = AddAttachment(doc, attachment.Attachment{
|
||||||
Name: embedName,
|
Name: embedName,
|
||||||
Description: description,
|
Description: description,
|
||||||
MIMEType: "text/xml",
|
MIMEType: "text/xml",
|
||||||
|
|||||||
@@ -0,0 +1,317 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitlab.com/romalor/pdflib/pkg/components/attachment"
|
||||||
|
"gitlab.com/romalor/pdflib/pkg/core"
|
||||||
|
"gitlab.com/romalor/pdflib/pkg/pdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddAttachment embeds data as a file attachment.
|
||||||
|
// The att.Name field specifies the attachment name.
|
||||||
|
func AddAttachment(d *pdf.Document, att attachment.Attachment, data []byte) error {
|
||||||
|
if !d.IsWritable() || d.Writer() == nil {
|
||||||
|
return pdf.ErrNotWritable
|
||||||
|
}
|
||||||
|
|
||||||
|
if att.Name == "" {
|
||||||
|
return errors.New("attachment name cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply defaults
|
||||||
|
modDate := att.ModDate
|
||||||
|
if modDate.IsZero() {
|
||||||
|
modDate = time.Now()
|
||||||
|
}
|
||||||
|
relationship := att.Relationship
|
||||||
|
if relationship == "" {
|
||||||
|
relationship = "Unspecified"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guess MIME type if not provided
|
||||||
|
mimeType := att.MIMEType
|
||||||
|
if mimeType == "" {
|
||||||
|
mimeType = guessMIMEType(att.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate checksum
|
||||||
|
checksum := md5.Sum(data)
|
||||||
|
|
||||||
|
// Create embedded file stream
|
||||||
|
efStreamDict := core.NewDictionary()
|
||||||
|
efStreamDict.Set(core.Name("Type"), core.Name("EmbeddedFile"))
|
||||||
|
if mimeType != "" {
|
||||||
|
efStreamDict.Set(core.Name("Subtype"), core.Name(mimeType))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Params dictionary
|
||||||
|
params := core.NewDictionary()
|
||||||
|
params.Set(core.Name("Size"), core.Integer(len(data)))
|
||||||
|
params.Set(core.Name("ModDate"), core.String(Format(modDate)))
|
||||||
|
params.Set(core.Name("CheckSum"), core.HexString(checksum[:]))
|
||||||
|
efStreamDict.Set(core.Name("Params"), params)
|
||||||
|
|
||||||
|
// Create the stream (compression is handled by the writer)
|
||||||
|
var efStream *core.Stream
|
||||||
|
if !att.NoCompress {
|
||||||
|
efStreamDict.Set(core.Name("Filter"), core.Name("FlateDecode"))
|
||||||
|
}
|
||||||
|
efStream = core.NewStreamFromBytes(efStreamDict, data)
|
||||||
|
efStreamRef := d.Writer().Add(efStream)
|
||||||
|
|
||||||
|
// Create EF (embedded files) dictionary
|
||||||
|
efDict := core.NewDictionary()
|
||||||
|
efDict.Set(core.Name("F"), efStreamRef)
|
||||||
|
efDict.Set(core.Name("UF"), efStreamRef) // Unicode-compatible version
|
||||||
|
|
||||||
|
// Create file specification dictionary
|
||||||
|
fileSpec := core.NewDictionary()
|
||||||
|
fileSpec.Set(core.Name("Type"), core.Name("Filespec"))
|
||||||
|
fileSpec.Set(core.Name("F"), core.String(att.Name))
|
||||||
|
fileSpec.Set(core.Name("UF"), core.String(att.Name)) // Unicode filename
|
||||||
|
fileSpec.Set(core.Name("EF"), efDict)
|
||||||
|
|
||||||
|
if att.Description != "" {
|
||||||
|
fileSpec.Set(core.Name("Desc"), core.String(att.Description))
|
||||||
|
}
|
||||||
|
|
||||||
|
if relationship != "Unspecified" {
|
||||||
|
fileSpec.Set(core.Name("AFRelationship"), core.Name(relationship))
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSpecRef := d.Writer().Add(fileSpec)
|
||||||
|
|
||||||
|
// Update the EmbeddedFiles name tree
|
||||||
|
if err := addToEmbeddedFilesNameTree(d, att.Name, fileSpecRef); err != nil {
|
||||||
|
return fmt.Errorf("adding to embedded files tree: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addToEmbeddedFilesNameTree adds an entry to the EmbeddedFiles name tree.
|
||||||
|
func addToEmbeddedFilesNameTree(d *pdf.Document, name string, fileSpecRef core.Reference) error {
|
||||||
|
catalog, catalogRef, err := d.Resolver().Catalog()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get existing Names dictionary
|
||||||
|
var namesDict *core.Dictionary
|
||||||
|
var namesRef core.Reference
|
||||||
|
var namesIsRef bool
|
||||||
|
|
||||||
|
if namesObj, ok := catalog.Get(core.Name("Names")); ok {
|
||||||
|
if ref, isRef := namesObj.(core.Reference); isRef {
|
||||||
|
namesRef = ref
|
||||||
|
namesIsRef = true
|
||||||
|
}
|
||||||
|
namesDict, err = core.ResolveDict(d.Resolver(), namesObj)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("resolving Names dictionary: %w", err)
|
||||||
|
}
|
||||||
|
// Clone the dictionary
|
||||||
|
namesDict = namesDict.CloneDict()
|
||||||
|
} else {
|
||||||
|
// Create new Names dictionary
|
||||||
|
namesDict = core.NewDictionary()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get existing EmbeddedFiles name tree
|
||||||
|
var efDict *core.Dictionary
|
||||||
|
var efRef core.Reference
|
||||||
|
var efIsRef bool
|
||||||
|
|
||||||
|
if efObj, ok := namesDict.Get(core.Name("EmbeddedFiles")); ok {
|
||||||
|
if ref, isRef := efObj.(core.Reference); isRef {
|
||||||
|
efRef = ref
|
||||||
|
efIsRef = true
|
||||||
|
}
|
||||||
|
efDict, err = core.ResolveDict(d.Resolver(), efObj)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("resolving EmbeddedFiles dictionary: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build new name tree with the added entry
|
||||||
|
var newNamesArray core.Array
|
||||||
|
|
||||||
|
if efDict != nil {
|
||||||
|
// Get existing entries
|
||||||
|
entries, err := collectNameTreeEntries(d, efDict)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("collecting existing entries: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new entry
|
||||||
|
entries = append(entries, nameTreeEntry{name: name, value: fileSpecRef})
|
||||||
|
|
||||||
|
// Sort by name
|
||||||
|
sort.Slice(entries, func(i, j int) bool {
|
||||||
|
return entries[i].name < entries[j].name
|
||||||
|
})
|
||||||
|
|
||||||
|
// Build names array
|
||||||
|
newNamesArray = make(core.Array, 0, len(entries)*2)
|
||||||
|
for _, entry := range entries {
|
||||||
|
newNamesArray = append(newNamesArray, core.String(entry.name), entry.value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create new names array with single entry
|
||||||
|
newNamesArray = core.Array{core.String(name), fileSpecRef}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new EmbeddedFiles dictionary
|
||||||
|
newEFDict := core.NewDictionary()
|
||||||
|
newEFDict.Set(core.Name("Names"), newNamesArray)
|
||||||
|
|
||||||
|
// Update or create EmbeddedFiles entry
|
||||||
|
if efIsRef {
|
||||||
|
if err := d.Writer().Modify(efRef, newEFDict); err != nil {
|
||||||
|
return fmt.Errorf("modifying EmbeddedFiles: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
namesDict.Set(core.Name("EmbeddedFiles"), newEFDict)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update or create Names dictionary
|
||||||
|
if namesIsRef {
|
||||||
|
if !efIsRef {
|
||||||
|
// We added a new EmbeddedFiles entry, need to update Names
|
||||||
|
if err := d.Writer().Modify(namesRef, namesDict); err != nil {
|
||||||
|
return fmt.Errorf("modifying Names: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update catalog
|
||||||
|
newCatalog := catalog.CloneDict()
|
||||||
|
newCatalog.Set(core.Name("Names"), namesDict)
|
||||||
|
|
||||||
|
// Extend AF array
|
||||||
|
afArr := core.Array{fileSpecRef}
|
||||||
|
newCatalog.Set(core.Name("AF"), afArr)
|
||||||
|
|
||||||
|
if err := d.Writer().Modify(catalogRef, newCatalog); err != nil {
|
||||||
|
return fmt.Errorf("modifying catalog: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nameTreeEntry represents a name-value pair from a name tree.
|
||||||
|
type nameTreeEntry struct {
|
||||||
|
name string
|
||||||
|
value core.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectNameTreeEntries collects all entries from a name tree.
|
||||||
|
func collectNameTreeEntries(d *pdf.Document, dict *core.Dictionary) ([]nameTreeEntry, error) {
|
||||||
|
var entries []nameTreeEntry
|
||||||
|
|
||||||
|
// Check for Names array (leaf node)
|
||||||
|
if namesObj, ok := dict.Get(core.Name("Names")); ok {
|
||||||
|
namesArray, err := core.ResolveArray(d.Resolver(), namesObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Names array has pairs: [name1, value1, name2, value2, ...]
|
||||||
|
for i := 0; i+1 < len(namesArray); i += 2 {
|
||||||
|
var name string
|
||||||
|
switch n := namesArray[i].(type) {
|
||||||
|
case core.String:
|
||||||
|
name = string(n)
|
||||||
|
case core.HexString:
|
||||||
|
name = string(n)
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entries = append(entries, nameTreeEntry{name: name, value: namesArray[i+1]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Kids array (intermediate node)
|
||||||
|
if kidsObj, ok := dict.Get(core.Name("Kids")); ok {
|
||||||
|
kidsArray, err := core.ResolveArray(d.Resolver(), kidsObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, kid := range kidsArray {
|
||||||
|
kidDict, err := core.ResolveDict(d.Resolver(), kid)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kidEntries, err := collectNameTreeEntries(d, kidDict)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entries = append(entries, kidEntries...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// guessMIMEType guesses the MIME type from a filename.
|
||||||
|
func guessMIMEType(filename string) string {
|
||||||
|
ext := filepath.Ext(filename)
|
||||||
|
if ext == "" {
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common MIME types
|
||||||
|
mimeTypes := map[string]string{
|
||||||
|
".pdf": "application/pdf",
|
||||||
|
".txt": "text/plain",
|
||||||
|
".html": "text/html",
|
||||||
|
".htm": "text/html",
|
||||||
|
".xml": "application/xml",
|
||||||
|
".json": "application/json",
|
||||||
|
".csv": "text/csv",
|
||||||
|
".png": "image/png",
|
||||||
|
".jpg": "image/jpeg",
|
||||||
|
".jpeg": "image/jpeg",
|
||||||
|
".gif": "image/gif",
|
||||||
|
".svg": "image/svg+xml",
|
||||||
|
".mp3": "audio/mpeg",
|
||||||
|
".mp4": "video/mp4",
|
||||||
|
".zip": "application/zip",
|
||||||
|
".doc": "application/msword",
|
||||||
|
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
".xls": "application/vnd.ms-excel",
|
||||||
|
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
}
|
||||||
|
|
||||||
|
if mime, ok := mimeTypes[ext]; ok {
|
||||||
|
return mime
|
||||||
|
}
|
||||||
|
return "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatPDFDate formats a time.Time as a PDF date string.
|
||||||
|
// The format is: D:YYYYMMDDHHmmSSOHH'mm'
|
||||||
|
// where O is the timezone indicator (+, or -) and HH'mm' is the offset.
|
||||||
|
func Format(t time.Time) string {
|
||||||
|
// Get timezone offset
|
||||||
|
_, offset := t.Zone()
|
||||||
|
offsetHours := offset / 3600
|
||||||
|
offsetMins := (offset % 3600) / 60
|
||||||
|
|
||||||
|
var sign byte = '+'
|
||||||
|
if offsetHours < 0 {
|
||||||
|
sign = '-'
|
||||||
|
offsetHours = -offsetHours
|
||||||
|
offsetMins = -offsetMins
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'",
|
||||||
|
t.Year(), t.Month(), t.Day(),
|
||||||
|
t.Hour(), t.Minute(), t.Second(),
|
||||||
|
sign, offsetHours, offsetMins)
|
||||||
|
}
|
||||||
+101
-8
@@ -11,27 +11,120 @@ const (
|
|||||||
FacturXPrefix = "fx:"
|
FacturXPrefix = "fx:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PDFAProperty struct {
|
||||||
|
Name string `xmp:"pdfaProperty:name"`
|
||||||
|
ValueType string `xmp:"pdfaProperty:valueType"`
|
||||||
|
Category string `xmp:"pdfaProperty:category"`
|
||||||
|
Description string `xmp:"pdfaProperty:description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PDFASchema struct {
|
||||||
|
Schema string `xmp:"pdfaSchema:schema"`
|
||||||
|
NamespaceURI string `xmp:"pdfaSchema:namespaceURI"`
|
||||||
|
Prefix string `xmp:"pdfaSchema:prefix"`
|
||||||
|
Property []PDFAProperty `xmp:"pdfaSchema:property"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PDFAExtensionData struct {
|
||||||
|
Schemas [1]PDFASchema `xmp:"pdfaExtension:schemas,bag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PDFAExtensionModel struct {
|
||||||
|
PDFAExtensionData
|
||||||
|
|
||||||
|
xmpbase.XmpBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x PDFAExtensionModel) Can(nsName string) bool {
|
||||||
|
return nsName == "pdfaExtension"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x PDFAExtensionModel) Namespaces() xmp.NamespaceList {
|
||||||
|
return xmp.NamespaceList{
|
||||||
|
{
|
||||||
|
Name: "pdfaSchema",
|
||||||
|
URI: "http://www.aiim.org/pdfa/ns/schema#",
|
||||||
|
Factory: defaultFactory,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pdfaExtension",
|
||||||
|
URI: "http://www.aiim.org/pdfa/ns/extension/",
|
||||||
|
Factory: defaultFactory,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pdfaProperty",
|
||||||
|
URI: "http://www.aiim.org/pdfa/ns/property#",
|
||||||
|
Factory: defaultFactory,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultFactory(name string) xmp.Model {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func addFacturXXmpData(data []byte) ([]byte, error) {
|
func addFacturXXmpData(data []byte) ([]byte, error) {
|
||||||
|
// --- Register Factur-X namespace ---
|
||||||
|
xmp.Register(&xmp.Namespace{
|
||||||
|
Name: "fx",
|
||||||
|
URI: FacturXUri,
|
||||||
|
Factory: defaultFactory,
|
||||||
|
})
|
||||||
|
|
||||||
doc := &xmp.Document{}
|
doc := &xmp.Document{}
|
||||||
err := xmp.Unmarshal(data, doc)
|
err := xmp.Unmarshal(data, doc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Register Factur-X namespace ---
|
model := &PDFAExtensionModel{
|
||||||
ns := &xmp.Namespace{
|
PDFAExtensionData: PDFAExtensionData{
|
||||||
Name: "fx",
|
Schemas: [1]PDFASchema{
|
||||||
URI: FacturXUri,
|
{
|
||||||
Factory: func(name string) xmp.Model {
|
Schema: "Factur-X PDFA Extension Schema",
|
||||||
return &xmpbase.XmpBase{}
|
NamespaceURI: "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#",
|
||||||
|
Prefix: "fx",
|
||||||
|
Property: []PDFAProperty{
|
||||||
|
{
|
||||||
|
Name: "DocumentType",
|
||||||
|
ValueType: "Text",
|
||||||
|
Category: "external",
|
||||||
|
Description: "Factur-X document type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "DocumentFileName",
|
||||||
|
ValueType: "Text",
|
||||||
|
Category: "external",
|
||||||
|
Description: "Attached XML file name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Version",
|
||||||
|
ValueType: "Text",
|
||||||
|
Category: "external",
|
||||||
|
Description: "Factur-X version",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ConformanceLevel",
|
||||||
|
ValueType: "Text",
|
||||||
|
Category: "external",
|
||||||
|
Description: "Factur-X profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
xmp.Register(ns)
|
_, err = doc.AddModel(model)
|
||||||
_, err = doc.MakeModel(ns)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doc.FindModel(&xmp.Namespace{
|
||||||
|
Name: "",
|
||||||
|
URI: "",
|
||||||
|
Factory: nil,
|
||||||
|
})
|
||||||
|
|
||||||
// --- Set Factur-X properties ---
|
// --- Set Factur-X properties ---
|
||||||
err = doc.SetPath(xmp.PathValue{
|
err = doc.SetPath(xmp.PathValue{
|
||||||
Path: FacturXPrefix + "ConformanceLevel",
|
Path: FacturXPrefix + "ConformanceLevel",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func main() {
|
|||||||
Name: path.Base(exeName),
|
Name: path.Base(exeName),
|
||||||
Usage: "Pdf xml invoice helper cli",
|
Usage: "Pdf xml invoice helper cli",
|
||||||
UseShortOptionHandling: true,
|
UseShortOptionHandling: true,
|
||||||
Version: "1.0.0",
|
Version: "1.0.1",
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "extract",
|
Name: "extract",
|
||||||
|
|||||||
Reference in New Issue
Block a user