Du har bygget en Factur-X-faktura, og alle container-tjek består. Kataloget bærer et /AF-array, EmbeddedFiles-navnetræet opløses til den rigtige filspecifikation, den indlejrede factur-x.xml har det korrekte /AFRelationship som Alternative, og den indbyggede ValidateFacturXInvoice returnerer 1. Så kører du den samme fil gennem veraPDF, den reference-checker, skatteportaler bruger, og den dømmer, at hele dokumentet ikke er en gyldig PDF/A-3. Strukturen er rigtig. Metadataene er problemet, og fejlen er en af de nemmeste at overse i hele e-faktura-arbejdsgangen
Årsagen er værd at forstå fuldt ud, fordi den forklarer en klasse af PDF/A-fejl, der intet har at gøre med den synlige side eller vedhæftningen, og alt at gøre med, hvordan XMP beskriver sig selv. Dette er fælden, der gemmer sig bag et grønt container-tjek
De fire egenskaber der dumper filen
En Factur-X-faktura skriver fire brugerdefinerede egenskaber ind i sin XMP-pakke, så downstream-software kan læse fakturaprofilen uden at parse den indlejrede XML. De lever i Factur-X-namespacet under fx-præfikset: fx:DocumentFileName, fx:DocumentType, fx:Version og fx:ConformanceLevel. De er præcis de metadata, en læser har brug for at vide, at denne PDF bærer en EN 16931-faktura ved navn factur-x.xml ved version 1.0
Ingen af disse fire egenskaber er en del af noget XMP-skema, som PDF/A foruddefinerer. Dublin Core-, XMP Basic-, PDF- og PDF/A-identifikationsskemaerne er kendt af en overensstemmende læser, men fx: er ikke. Når veraPDF gennemløber XMP'en og når en egenskab, hvis namespace den ikke genkender, leder den efter en deklaration, der ville fortælle den, hvad egenskaben betyder. Hvis den deklaration mangler, rapporterer den en fejl i forhold til ISO 19005-3 klausul 6.6.2.3.1, som kræver, at enhver egenskab, der ikke er hentet fra et foruddefineret skema, beskrives i et PDF/A-udvidelsesskema. Fire udeklarerede egenskaber, fire måder for filen at blive afvist på, og ikke en eneste af dem er synlig for et container-tjek
Hvorfor PDF/A afviser en bar brugerdefineret egenskab
Reglen ser pedantisk ud, indtil man husker, hvad PDF/A er til for. Formatet eksisterer, for at en fil kan åbnes og forstås årtier fra nu, af software der aldrig fik noget at vide om konventionerne i 2026. En overensstemmende læser forventes at give mening til dokumentet ud fra dokumentet alene, uden noget eksternt register at konsultere
Brugerdefinerede metadata bryder det løfte, medmindre filen bærer sin egen beskrivelse. Givet en bar fx:ConformanceLevel-egenskab kan en fremtidig læser ikke kende det namespace-URI, fx-præfikset binder til, om værdien er tekst eller en dato eller et heltal, eller om egenskaben beskriver selve dokumentet eller en ekstern ressource. PDF/A-udvidelsesskemamekanismen lukker det hul. Den lader filen deklarere, i en fast XMP-struktur, namespacet, præfikset, og for hver egenskab en værditype og en kategori af internal eller external. Når den deklaration først er til stede, er egenskaben selvbeskrivende, og klausul 6.6.2.3.1 er tilfredsstillet. Uden den har validatoren intet andet valg end at behandle egenskaben som uforståelig og dumpe filen. Kategoridistinktionen betyder noget her: fakturaegenskaber som disse beskriver data, der kommer fra uden for PDF-processoren, så de deklareres external frem for internal
Hvad udvidelsesskema-deklarationen indeholder
Deklarationen er en rdf:Description i XMP-pakken, der bruger de tre AIIM-definerede namespaces pdfaExtension, pdfaSchema og pdfaProperty. Inde i en pdfaExtension:schemas-pose sidder én skemapost, der navngiver Factur-X-skemaet, giver dets pdfaSchema:namespaceURI og pdfaSchema:prefix, og derefter lister de fire egenskaber i en pdfaSchema:property-sekvens. Hver egenskab bærer et navn, en pdfaProperty:valueType som Text, og en pdfaProperty:category som external. Den illustrative markup nedenfor viser formen på den blok
Namespace-URI'et og præfikset er ikke faste strenge. De følger profilen. Et Factur-X-dokument bruger urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0# med fx-præfikset, mens en ZUGFeRD 2.0-fil valgt gennem zugferd-invoice.xml opløses til et andet URI under sit eget skemanavn. Udvidelsesskemaet skal deklarere det samme namespace-URI, som egenskabsblokken rent faktisk bruger, ellers kan validatoren stadig ikke forbinde de to. PDFlibPas afleder begge værdier fra filnavnet og versionen, du videregiver, så deklarationen og egenskabsblokken altid stemmer overens
Hvordan helperen skriver begge halvdele sammen
I PDFlibPas samler du ikke den XML i hånden. Du sætter dokumentet i en PDF/A-3-tilstand og kalder én metode. Den første ting at fastlægge er overensstemmelsesflaget, fordi Factur-X kræver PDF/A-3. Kald til SetPDFAMode(7) vælger PDF/A-3u-niveauet, som sætter pdfaid:part til 3 og pdfaid:conformance til U i identifikationsskemaet. XMP-pakken bærer nu den rigtige del og overensstemmelse, før nogen fakturameta-data overhovedet tilføjes
Et enkelt kald til AddFacturXAssociatedFileFromString gør det arbejde, som den dumpende fil manglede. Den indlejrer XML'en som en PDF/A-3-tilknyttet fil med det forhold, du navngav, og den registrerer de fire fx-egenskaber sammen med skemanavnet, namespace-URI'et og præfikset for den valgte profil. Når dokumentet gemmes, injicerer et internt trin ved navn ApplyFacturXMetadata både egenskabsblokken og den matchende pdfaExtension:schemas-deklaration i XMP-pakken, så de brugerdefinerede egenskaber ankommer færdigbeskrevne. Metoden returnerer 0, hvis dokumentet ikke er i en PDF/A-3-tilstand, eller hvis XML'en ikke matcher den deklarerede profil, hvilket er den samme vagt, der forhindrer en misdannet faktura i overhovedet at nå filen
Den blinde vinkel container-tjekket ikke kan se
Dette er den del, der skal nævnes i klartekst, fordi det er årsagen til, at fejlen skjuler sig. ValidateFacturXInvoice tjekker containeren. Den bekræfter, at kataloget har en /AF-post, EmbeddedFiles-navnetræet er til stede, faktura-XML'en eksisterer, det indlejrede filnavn matcher profilen, retningslinje-ID'et i XML'en stemmer overens med overensstemmelsesniveauet, og /AFRelationship er en, PDF/A-3 tillader. Det er rigtige tjek, og de fanger rigtige fejl. GetFacturXValidationIssues rapporterer dem ved navn, med identifikatorer som MissingCatalogAF, NotPDFA3, ConformanceGuidelineMismatch, InvalidAFRelationship og InvalidFileNameProfile
Hvad den ikke tjekker, er om XMP-udvidelsesskemaet er til stede og korrekt. En fil, hvis container er fejlfri, men hvis fx-egenskaber er udeklarerede, passerer hvert problem-tjek og returnerer 1, fordi intet på den liste inspicerer pdfaExtension:schemas-blokken. Det er præcis derfor, en håndbygget faktura, eller en produceret af en pipeline, der skrev egenskabsblokken uden deklarationen, kan sejle gennem den indbyggede validator og stadig dumpe veraPDF på klausul 6.6.2.3.1. Container-validatoren og PDF/A-metadata-validatoren besvarer forskellige spørgsmål, og kun den fulde PDF/A-checker besvarer det andet
Læsning af problemer så du ved hvilket lag der gik i stykker
Fordi de to lag fejler uafhængigt, er den rigtige diagnostiske vane at læse container-problemerne først og behandle et rent resultat som en udtalelse udelukkende om containeren, aldrig om PDF/A-metadata. Kør den indbyggede validering, indsaml problemlisten, og handl på den, før du rækker ud efter et eksternt værktøj
Når det kald returnerer et problemnavn, er fejlen i containeren, og meddelelsen fortæller dig hvilken del. Når det returnerer rent, og veraPDF stadig afviser filen, er fejlen næsten altid XMP-udvidelsesskemaet, og rettelsen er at lade AddFacturXAssociatedFileFromString skrive metadataene frem for at konstruere egenskabsblokken selv. At holde de to spørgsmål adskilt i dit eget sind er, hvad der forvandler en forvirrende afvisning til en én-linjes diagnose: containerproblemer kommer til overfladen gennem problemlisten, skemadeklarations-problemer kommer kun til overfladen gennem en PDF/A-validator, og forveksling af de to er, hvad der lader fejlen skjule sig
Det bredere PDF/A- og PDF/UA-overensstemmelsesbillede, herunder hvordan man kører en preflight-gennemgang før en fil forlader sit build, er dækket i PDF/A- og PDF/UA-preflight-gennemgangen. Hvis din faktura også skal være tilgængelig, er strukturtræet, som PDF/A-3a og tagged PDF afhænger af, emnet for tagged-PDF-tilgængelighedsartiklen. Udvidelsesskemahåndteringen beskrevet her leveres som del af PDFlibPas Delphi PDF Library ved siden af understøttelsen af Factur-X-, ZUGFeRD- og XRechnung-profiler, der er dokumenteret på tværs af denne blog