pCOS Cookbook

cookbook

interchange/zugferd_retrieve_XML updated

Retrieve XML invoice data and explanatory documents from ZUGFeRD 1.0, 2.0, 2.1 or Factur-X invoices

Download Java Code  Show Output  Show Input (zugferd_invoice.pdf) 

/*
 * Retrieve XML invoice data and explanatory documents from ZUGFeRD 1.0, 2.0,
 * 2.1 or Factur-X documents.
 *
 * If explanatory documents (additional attachments for invoice verification)
 * according to Factur-X 1.0.05 or ZUGFeRD 2.x are found their names are listed.
 *
 * Required software: pCOS interface 8 (PDFlib+PDI/PPS 9, TET 4.1, PLOP 4.2)
 * Required data: PDF document
 */
package com.pdflib.cookbook.pcos.interchange;

import java.io.FileOutputStream;
import java.io.OutputStream;

import com.pdflib.IpCOS;
import com.pdflib.cookbook.pcos.pcos_cookbook_example;

public class zugferd_retrieve_XML extends pcos_cookbook_example {

    /* This is where the data files are. Adjust as necessary. */
    private final static String SEARCH_PATH = "../input";

    public void example_code(IpCOS p, int doc) throws Exception {

        String filename = p.pcos_get_string(doc, "filename");
        System.out.println("Input file name '" + filename + "'");

        get_zugferd_invoice(p, filename, doc);
    }

    private void bad_format_exception(String filename, String text)
        throws Exception
    {
        throw new Exception(
            "Input document '" + filename
            + "' doesn't conform to the ZUGFeRD or Factur-X standard\n("
            + text + ")");
    }
    
    private void get_zugferd_invoice(IpCOS p, String filename, int doc)
        throws Exception {

        // The name of the XML invoice data varies among standards
        final String[] xml_invoice_name = {
                "ZUGFeRD-invoice.xml",  /* ZUGFeRD 1.0 */
                "zugferd-invoice.xml",  /* ZUGFeRD 2.0 */
                "factur-x.xml"          /* Factur-X and ZUGFeRD 2.1 */
        };

        /*
         * ZUGFeRD/Factur-X XML invoice data is stored as associated file
         * in the /AF array at the document level.
         */
        
        if (p.pcos_get_string(doc, "type:/Root/AF").equals("array")) {
            boolean found = false;
            
            int associated_files_count = (int) p.pcos_get_number(doc, "length:/Root/AF");
            
            for (int i = 0; i < associated_files_count; i += 1) {
                String associated_file = "/Root/AF[" + i + "]";

                /*
                 * PDF/A-3 requires the presence of the /UF entry in the
                 * File Specification Dictionarry
                 */
                String objtype = p.pcos_get_string(doc, "type:"
                    + associated_file + "/UF");

                if (objtype.equals("string")) {
                    String name = p.pcos_get_string(doc, associated_file + "/UF");

                    /* Check standard invoice XML file names */
                    if (xml_invoice_name[0].equals(name) ||
                        xml_invoice_name[1].equals(name) ||
                        xml_invoice_name[2].equals(name)) {
                        /*
                         * There must be a corresponding "/UF" entry in the
                         * EF dictionary. Check whether it is a stream object.
                         */
                        objtype = p.pcos_get_string(doc, "type:"
                            + associated_file + "/EF/UF");

                        if (objtype.equals("stream")) {
                            /*
                             * Get the contents of the invoice and write it to a
                             * file.
                             */
                            byte[] invoice_contents = p.pcos_get_stream(doc,
                                "", associated_file + "/EF/UF");
    
                            OutputStream os = new FileOutputStream(name);
                            os.write(invoice_contents);
                            os.close();
    
                            found = true;
                            System.out
                                .println(
                                    "Invoice attachment written to file '" + name + "'");
                        }
                        else
                        {
                            bad_format_exception(filename,
                                "/UF embedded file stream with XML file "
                                + "contents is missing");
                        }
                    }
                    else {
                    	/* Attachments with other names are explanatory documents */
                    	System.out.println("Found explanatory document '" + name + "'");
                    }
                }
                else {
                    System.err.println("Warning: /UF key is missing in "
                        + "associated file number" + i);
                }
            }

            if (!found) {
                bad_format_exception(filename,
                    "Didn't find any invoice attachment with standard name (\""
                        + xml_invoice_name[0] + "\", \"" + xml_invoice_name[1] +  "\", \"" + xml_invoice_name[2] + "\"");
                
            }
            if (associated_files_count == 1)
            	System.out.println("No explanatory documents found");
        }
        else {
            bad_format_exception(filename,
                "PDF document does not contain any associated files");
        }
    }

    public zugferd_retrieve_XML(String[] argv, String readable_name,
        String search_path) {
        super(argv, readable_name, search_path);
    }

    public static void main(String argv[]) {
        zugferd_retrieve_XML example = new zugferd_retrieve_XML(argv,
            "Extract ZUGFeRD or Factur-X invoice", SEARCH_PATH);
        example.execute();
    }
}