diff --git a/.gitignore b/.gitignore
index a1c2a23..2fccb66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,25 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+
+*.bak
+.adf
+.data
+.idea
+**/.classpath
+**/.project
+**/.settings
+**/build
+**/dist
+**/nbproject
+**/target
+**/*.log
+**/nb-configuration.xml
+**/rebel.xml
+**/rebel-remote.xml
+.gradle
+**/*.iml
+**/.factorypath
+buildSrc
+**/.idea
+**/Debug
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..579bdda
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,30 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [0.9.3] - 2022-04-04
+### Changed
+- uptake javamelody 1.91.0
+- uptake maven plugins
+
+## [0.9.2] - 2022-01-31
+### Added
+- 2 tests
+
+### Changed
+- cleanup samples
+- uptake apache fop 2.7
+- uptake javamelody 1.90.0
+
+## [0.9.1] - 2022-01-28
+### Added
+- initial version
+- apache fop 2.6
+
+[Unreleased]: http://gitlab.pdv.lan/oliver1/fop4apex/compare/0.9.3...master
+[0.9.3]: http://gitlab.pdv.lan/oliver1/fop4apex/compare/0.9.2...0.9.3
+[0.9.2]: hhttp://gitlab.pdv.lan/oliver1/fop4apex/-/tags/0.9.2
diff --git a/LICENSE b/LICENSE
index 261eeb9..790b76e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -178,7 +178,7 @@
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
+ boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2022 Oliver Warz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index a0c8d46..94f3b3c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,46 @@
-# fop4apex
\ No newline at end of file
+# fop4apex
+Servlet for Oracle APEX to run PDF Reports based on Apache FOP
+
+Fahrdienst-Anwendung / Kostenblatt
+
+* Uses Apache FOP for rendering
+https://xmlgraphics.apache.org/fop/
+* Uses JavaMelody for monitoring
+https://github.com/javamelody/javamelody/wiki
+* Use Java 8 LTS (also tested with Java 17)
+
+## Run tests
+`mvn test`
+
+## Build
+`mvn package verify`
+
+## Upgrade
+* set new version in pom.xml
+* check dependent libraries for updates
+* run tests and build
+
+## Installation
+* rename target/fop4apex*.war to fop4apex.war
+* copy fop4apex.war to tomcat webapps folder
+* Oracle APEX - Sample Settings
+ * PrintServer External (Apache FOP)
+ * Protocol HTTP / HTTPS
+ * Host 127.0.0.1
+ * Port 8080
+ * Script: /fop4apex/pdf
+ * Timeout 300
+### Debugging
+Add to Tomcat logging.properties:
+```
+org.apache.tomcat.util.http.Parameters.level = ALL
+de.pdv.apex.level = ALL
+```
+
+### Deploy to tomcat 9.x (IntelliJ / Netbeans)
+Run http://localhost:port/
+
+Example:
+* http://localhost:8080/fop4apex_war_exploded/
+* http://localhost:8080/fop4apex_war_exploded/monitoring
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..c85a3b2
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,134 @@
+
+
+ 4.0.0
+
+ de.pdv.apex
+ fop4apex
+ 0.9.3
+ fop4apex
+ war
+ https://www.pdv.de
+
+
+ UTF-8
+ 1.8
+ 1.8
+ 5.8.2
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+ provided
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.version}
+ test
+
+
+
+ org.apache.pdfbox
+ pdfbox
+ 2.0.25
+ test
+
+
+
+
+ org.apache.xmlgraphics
+ fop-core
+ 2.7
+ compile
+
+
+
+
+ net.bull.javamelody
+ javamelody-core
+ 1.91.0
+ compile
+
+
+
+
+
+ org.apache.pdfbox
+ fontbox
+ 2.0.25
+ compile
+
+
+
+ commons-io
+ commons-io
+ 2.11.0
+ compile
+
+
+
+ commons-logging
+ commons-logging
+ 1.2
+ compile
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 3.3.2
+
+
+ org.owasp
+ dependency-check-maven
+ 7.0.4
+
+
+
+ check
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M6
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/de/pdv/apex/PdfServlet.java b/src/main/java/de/pdv/apex/PdfServlet.java
new file mode 100644
index 0000000..b0f1d2b
--- /dev/null
+++ b/src/main/java/de/pdv/apex/PdfServlet.java
@@ -0,0 +1,147 @@
+package de.pdv.apex;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.apps.MimeConstants;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * @author oliver1
+ */
+@WebServlet(name = "pdf", urlPatterns = {"/pdf"})
+public class PdfServlet extends HttpServlet {
+ private static final Logger logger = Logger.getLogger(PdfServlet.class.getName());
+
+ private final TransformerFactory tFactory = TransformerFactory.newInstance();
+
+ public void init() {
+ }
+
+ //
+
+ /**
+ * Handles the HTTP GET method.
+ *
+ * @param request servlet request
+ * @param response servlet response
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException {
+ logger.log(Level.FINEST,"Finest output");
+ logger.log(Level.FINER,"Finer output");
+ logger.log(Level.FINE,"Fine output");
+ logger.log(Level.INFO,"Info output");
+ logger.log(Level.INFO,"doGet");
+ try {
+ response.setContentType("application/pdf");
+ // response.setDateHeader("Expires", System.currentTimeMillis() + cacheExpiringDuration * 1000);
+ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, response.getOutputStream());
+ Transformer transformer = tFactory.newTransformer();
+ InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("samples/helloWorld.fo");
+ Source src = new StreamSource(inputStream);
+ Result res = new SAXResult(fop.getDefaultHandler());
+ transformer.transform(src, res);
+ logger.log(Level.INFO,"Process complete");
+ } catch (Exception ex) {
+ throw new ServletException(ex);
+ }
+ }
+
+
+ /**
+ * Handles the HTTP POST method.
+ *
+ * @param request servlet request
+ * @param response servlet response
+ * @throws ServletException if a servlet-specific error occurs
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException {
+ ServletContext context = getServletContext();
+ logger.log(Level.FINEST,"Finest output");
+ logger.log(Level.FINER,"Finer output");
+ logger.log(Level.FINE,"Fine output");
+ logger.log(Level.INFO,"Info output");
+ logger.log(Level.INFO,"doPost");
+ try {
+ String contentType = request.getContentType();
+ String templateFile = "template.fo";
+ String templateData = "xml data";
+ // String pdfFileName = "";
+
+ if (request.getParameter("template") != null)
+ templateFile = request.getParameter("template");
+ if (request.getParameter("xml") != null)
+ templateData = request.getParameter("xml");
+ logger.log(Level.FINEST,"Working directory: " + (new File("dummy1.txt")).getAbsolutePath());
+ logger.log(Level.FINEST,"Template file: " + templateFile);
+ logger.log(Level.FINEST,"Template data: " + templateData);
+ logger.log(Level.FINEST,"Content type: " + contentType);
+
+ String pdfFileName = "Kostenblatt.pdf";
+ response.setContentType("application/pdf");
+ response.setHeader("Content-disposition", "attachment; filename=" + pdfFileName);
+ // response.setDateHeader("Expires", System.currentTimeMillis() + cacheExpiringDuration * 1000);
+ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+ FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+ // Construct fop with desired output format
+ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, response.getOutputStream());
+
+ // Setup XSLT
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer( new StreamSource(new StringReader(templateFile)));
+ // Set the value of a in the stylesheet
+ transformer.setParameter("versionParam", "2.0");
+
+ // Setup input for XSLT transformation
+ Source src = new StreamSource(new StringReader(templateData));
+
+ // Resulting SAX events (the generated FO) must be piped through to FOP
+ Result res = new SAXResult(fop.getDefaultHandler());
+
+ // Start XSLT transformation and FOP processing
+ transformer.transform(src, res);
+ logger.log(Level.INFO,"Process complete");
+
+ } catch (Exception e) {
+ context.log(e.getMessage(), e);
+ throw new ServletException(e.getMessage());
+ }
+ // processRequest(request, response);
+ }
+
+ /**
+ * Returns a short description of the servlet.
+ *
+ * @return a String containing servlet description
+ */
+ @Override
+ public String getServletInfo() {
+ return "APEX FOP Server";
+ }//
+
+ @Override
+ public void destroy() {
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/samples/helloWorld.fo b/src/main/resources/samples/helloWorld.fo
new file mode 100644
index 0000000..d9345b5
--- /dev/null
+++ b/src/main/resources/samples/helloWorld.fo
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+ Hello World!
+
+
+
diff --git a/src/main/webapp/META-INF/context.xml b/src/main/webapp/META-INF/context.xml
new file mode 100644
index 0000000..b09d605
--- /dev/null
+++ b/src/main/webapp/META-INF/context.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..39b755f
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,25 @@
+
+
+
+ javamelody
+ net.bull.javamelody.MonitoringFilter
+ true
+
+ update-check-disabled
+ true
+
+
+
+ javamelody
+ /*
+ REQUEST
+ ASYNC
+
+
+ net.bull.javamelody.SessionListener
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
new file mode 100644
index 0000000..6274d83
--- /dev/null
+++ b/src/main/webapp/index.jsp
@@ -0,0 +1,68 @@
+<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
+
+
+
+ Apache FOP for Oracle APEX
+
+
+
+JSP - Apache FOP (Formatting Objects Processor) integration for Oracle APEX
+
+<%--suppress HtmlUnknownTarget --%>
+pdf Servlet / Hello World / fo2pdf
+<%--suppress HtmlUnknownTarget --%>
+JavaMelody Monitoring
+Sample APEX Settings
+
+
+
+ | Parameter |
+ Value |
+
+
+
+ | PrintServer |
+ External (Apache FOP) |
+
+
+ | Protocol |
+ HTTP / HTTPS |
+
+
+ | Host |
+ 127.0.0.1 |
+
+
+ | Port |
+ 8080 |
+
+
+ | Script |
+ ${pageContext.request.contextPath}/pdf |
+
+
+ | Timeout |
+ 300 |
+
+
+
+Debugging
+
+# Add to logging.properties
+org.apache.tomcat.util.http.Parameters.level = ALL
+de.pdv.apex.level = ALL
+
+
+
+Server Info
+Server Version: <%= application.getServerInfo() %>
+Servlet Version: <%= application.getMajorVersion() %>.<%= application.getMinorVersion() %>
+JSP Version: <%= JspFactory.getDefaultFactory().getEngineInfo().getSpecificationVersion() %>
+Web Application Context Path = ${pageContext.request.contextPath}
+
+
+
\ No newline at end of file
diff --git a/src/test/java/de/pdv/apex/ExampleFO2PDFTest.java b/src/test/java/de/pdv/apex/ExampleFO2PDFTest.java
new file mode 100644
index 0000000..3c5d9d0
--- /dev/null
+++ b/src/test/java/de/pdv/apex/ExampleFO2PDFTest.java
@@ -0,0 +1,126 @@
+package de.pdv.apex;
+
+import org.apache.fop.apps.*;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.text.PDFTextStripper;
+import org.apache.pdfbox.text.PDFTextStripperByArea;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.nio.file.Files;
+import java.util.List;
+
+class ExampleFO2PDFTest {
+
+ // configure fopFactory as desired
+ private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+
+ /**
+ * Converts an FO file to a PDF file using FOP
+ *
+ * @param fo the FO file
+ * @param pdf the target PDF file
+ * @throws IOException In case of an I/O problem
+ */
+ public void convertFO2PDFHelper(InputStream fo, File pdf) throws IOException {
+
+ OutputStream out = null;
+
+ try {
+ FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+ // configure foUserAgent as desired
+
+ // Setup output stream. Note: Using BufferedOutputStream
+ // for performance reasons (helpful with FileOutputStreams).
+ out = new FileOutputStream(pdf);
+ out = new BufferedOutputStream(out);
+
+ // Construct fop with desired output format
+ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
+
+ // Setup JAXP using identity transformer
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer(); // identity transformer
+
+ // Setup input stream
+ Source src = new StreamSource(fo);
+
+ // Resulting SAX events (the generated FO) must be piped through to FOP
+ Result res = new SAXResult(fop.getDefaultHandler());
+
+ // Start XSLT transformation and FOP processing
+ transformer.transform(src, res);
+
+ // Result processing
+ FormattingResults foResults = fop.getResults();
+ @SuppressWarnings("rawtypes") List pageSequences = foResults.getPageSequences();
+ for (Object pageSequence : pageSequences) {
+ PageSequenceResults pageSequenceResults = (PageSequenceResults) pageSequence;
+ System.out.println("PageSequence "
+ + (String.valueOf(pageSequenceResults.getID()).length() > 0
+ ? pageSequenceResults.getID() : "")
+ + " generated " + pageSequenceResults.getPageCount() + " pages.");
+ }
+ System.out.println("Generated " + foResults.getPageCount() + " pages in total.");
+
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ System.exit(-1);
+ } finally {
+ assert out != null;
+ out.close();
+ }
+ }
+
+ @Test
+ void convertFO2PDF() throws Exception {
+ System.out.println("FOP ExampleFO2PDF\n");
+ System.out.println("Preparing...");
+
+ //Setup directories
+ File baseDir = new File(".");
+ File outDir = new File(baseDir, "target");
+ boolean bSuccess = outDir.mkdirs();
+ if (!bSuccess)
+ System.out.println("mkdirs result: false");
+
+ ExampleFO2PDFTest app = new ExampleFO2PDFTest();
+ //Setup input and output files
+ InputStream inputStream = app.getClass().getClassLoader().getResourceAsStream("samples/helloWorld.fo");
+ File pdfFile = new File(outDir, "ResultFO2PDF.pdf");
+
+ System.out.println("Input: XSL-FO (" + inputStream + ")");
+ System.out.println("Output: PDF (" + pdfFile + ")");
+ System.out.println();
+ System.out.println("Transforming...");
+
+ app.convertFO2PDFHelper(inputStream, pdfFile);
+
+ if (!pdfFile.exists())
+ throw new Exception("result file missing");
+
+ try (PDDocument document = PDDocument.load(pdfFile)) {
+ document.getClass();
+ if (!document.isEncrypted()) {
+ PDFTextStripperByArea stripper = new PDFTextStripperByArea();
+ stripper.setSortByPosition(true);
+ PDFTextStripper tStripper = new PDFTextStripper();
+ String pdfFileInText = tStripper.getText(document);
+ String lines[] = pdfFileInText.split("\\r?\\n");
+ for (String line : lines) {
+ System.out.println(line);
+ }
+ System.out.println("Pages: " + document.getNumberOfPages());
+ }
+ }
+ System.out.println("Filesize (Bytes): " + Files.size(pdfFile.toPath()));
+ System.out.println("Success!");
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/de/pdv/apex/ExampleXML2PDFTest.java b/src/test/java/de/pdv/apex/ExampleXML2PDFTest.java
new file mode 100644
index 0000000..1f80fd7
--- /dev/null
+++ b/src/test/java/de/pdv/apex/ExampleXML2PDFTest.java
@@ -0,0 +1,87 @@
+package de.pdv.apex;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+
+class ExampleXML2PDFTest {
+
+ @Test
+ void convertXML2PDF() throws Exception {
+ System.out.println("FOP ExampleXML2PDF\n");
+ System.out.println("Preparing...");
+
+ // Setup directories
+ File baseDir = new File(".");
+ File outDir = new File(baseDir, "target");
+ boolean bSuccess = outDir.mkdirs();
+ if (!bSuccess)
+ System.out.println("mkdirs result: false");
+
+ ExampleXML2PDFTest app = new ExampleXML2PDFTest();
+ // Setup input and output files
+ InputStream xsltFile = app.getClass().getClassLoader().getResourceAsStream("samples/kostenblatt_2014.xsl");
+ InputStream xmlFile = app.getClass().getClassLoader().getResourceAsStream("samples/kostenblatt_2014.xml");
+ File pdfFile = new File(outDir, "ResultXML2PDF.pdf");
+
+ System.out.println("Input: XML (" + xmlFile + ")");
+ System.out.println("Stylesheet: " + xsltFile);
+ System.out.println("Output: PDF (" + pdfFile + ")");
+ System.out.println();
+ System.out.println("Transforming...");
+
+ // configure fopFactory as desired
+ final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
+
+ FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
+ // configure foUserAgent as desired
+
+ // Setup output
+ OutputStream out = new java.io.FileOutputStream(pdfFile);
+ out = new java.io.BufferedOutputStream(out);
+
+ // Construct fop with desired output format
+ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
+
+ // Setup XSLT
+ TransformerFactory factory = TransformerFactory.newInstance();
+ Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));
+
+ // Set the value of a in the stylesheet
+ transformer.setParameter("versionParam", "2.0");
+
+ // Setup input for XSLT transformation
+ Source src = new StreamSource(xmlFile);
+
+ // Resulting SAX events (the generated FO) must be piped through to FOP
+ Result res = new SAXResult(fop.getDefaultHandler());
+
+ // Start XSLT transformation and FOP processing
+ transformer.transform(src, res);
+
+ //close
+ out.close();
+
+ if (!pdfFile.exists())
+ throw new Exception("result file missing");
+
+ PDDocument document = PDDocument.load(pdfFile);
+ System.out.println("Pages: " + document.getNumberOfPages());
+ System.out.println("Filesize (Bytes): " + Files.size(pdfFile.toPath()));
+ System.out.println("Success!");
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/samples/helloWorld.fo b/src/test/resources/samples/helloWorld.fo
new file mode 100644
index 0000000..d9345b5
--- /dev/null
+++ b/src/test/resources/samples/helloWorld.fo
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+ Hello World!
+
+
+
diff --git a/src/test/resources/samples/kostenblatt_2014.xml b/src/test/resources/samples/kostenblatt_2014.xml
new file mode 100644
index 0000000..89ea899
--- /dev/null
+++ b/src/test/resources/samples/kostenblatt_2014.xml
@@ -0,0 +1,685 @@
+
+
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A07
+ 7
+ Arbeitstage
+ (AT)
+ 23
+
+
+
+
+
+
+
+
+
+
+
+ 23
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A08
+ 8
+ Einsatztage
+ (ET)
+ 18
+
+
+
+
+
+
+
+
+
+
+
+ 18
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A09
+ 9
+ Nutzungsfrequenz
+ (ETx100/AT)
+ 78
+
+
+
+
+
+
+
+
+
+
+
+ 78
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A10
+ 10
+ gefahrene km
+
+ 2.832
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 2.832
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A11
+ 11
+ Kraftstoff getankt
+ (l/kg)
+ 241,24
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 241,24
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A12
+ 12
+ Kraftstoff bezahlt
+ (EUR je l/kg)
+ 285,72
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 285,72
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A13
+ 13
+ Kraftstoff Liter-Preis
+ (EUR je l/kg)
+ 1,18
+
+
+
+
+
+
+
+
+
+
+
+ 1,18
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A14
+ 14
+ Kraftstoff Verbrauch
+ (l je 100 km)
+ 8,52
+
+
+
+
+
+
+
+
+
+
+
+ 8,52
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A15
+ 15
+ Öl nachgefüllt
+ (l)
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A16
+ 16
+ Öl bezahlt
+ (EUR)
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A17
+ 17
+ Kosten Reparatur/Insp.
+ (EUR)
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A18
+ 18
+ Kosten Zubehör
+ (EUR)
+ 38,56
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 38,56
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A19
+ 19
+ Kraftfahrzeugsteuer
+ (EUR)
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+ 0,00
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A20
+ 20
+ Kosten Leasingrate
+ (EUR)
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 226,10
+ 0,00
+ 0,00
+ 0,00
+ 2.034,90
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A21
+ 21
+ Summe aller Kosten
+ (EUR)
+ 554,87
+ 230,59
+ 230,59
+ 230,59
+ 230,59
+ 226,10
+ 230,59
+ 230,59
+ 226,10
+ 0,00
+ 0,00
+ 0,00
+ 2.390,61
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A22
+ 22
+ km-Kosten
+ (EUR/km)
+ 0,20
+
+
+
+
+
+
+
+
+
+
+
+ 0,84
+
+
+ Dienstag , 18. Januar 2022
+ 2019
+ 605
+ THL 2-1
+ BMW 730d xDrive (Leasing-PKW)
+ WBA7C41010BR89892
+ 01.10.2018
+
+ 01.10.2018
+ nein
+
+ 0,00
+ 226,10
+ Regio/Fern
+ Diesel
+ F
+ 9.361
+ 12.193
+ 8
+ 4,49
+ 0,00
+ A23
+ 23
+ Kosten pro ET
+ (EUR/ET)
+ 30,83
+
+
+
+
+
+
+
+
+
+
+
+ 132,81
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/samples/kostenblatt_2014.xsl b/src/test/resources/samples/kostenblatt_2014.xsl
new file mode 100644
index 0000000..ac4172e
--- /dev/null
+++ b/src/test/resources/samples/kostenblatt_2014.xsl
@@ -0,0 +1,701 @@
+
+
+
+
+
+
+
+
+ 0.25pt
+ 0.25pt
+
+
+ start
+ 2
+ 0.0pt
+ preserve
+ 0.0pt
+ 0.0pt
+ 0.0pt
+ 0.0pt
+ 2
+
+
+ left
+
+
+ center
+
+
+ right
+
+
+ right
+ 5.4pt
+ 5.4pt
+
+
+ 5.4pt
+ 23.4pt
+
+
+ 13.872pt
+ 5.4pt
+
+
+ 5.4pt
+
+
+
+
+
+
+
+
+ 13.872pt
+
+
+ false
+
+
+ solid
+ solid
+
+
+ 5.15pt
+ top
+ 0.0pt
+ 5.15pt
+ 1
+ 0.0pt
+ 0.0pt
+
+
+
+
+
+ 7pt
+ 0.5pt
+ solid
+ black
+
+
+ 7pt
+ 16pt
+ 1mm
+ 1mm
+
+
+ 6pt
+ 16pt
+ 1mm
+ 1mm
+ italic
+
+
+ 8pt
+ 16pt
+ 1mm
+ 1mm
+
+
+ 1mm
+ 1mm
+
+
+ 1mm
+ 1mm
+
+
+
+ 8.0pt
+ 8.0pt
+ bold
+ Helvetica
+ 0.5pt
+ solid
+ black
+ #d6d6d6
+ bold
+
+
+ 6.0pt
+ 6.0pt
+ 0.5pt
+ solid
+ black
+ #d6d6d6
+
+
+ 14.0pt
+ 14.0pt
+ bold
+ Helvetica
+ 0.5pt
+ solid
+ black
+ black
+
+
+ 14.0pt
+ 14.0pt
+ bold
+ Helvetica
+ 0.0pt
+ solid
+ black
+ red
+
+
+ 3pt
+ 3pt
+ bold
+ Helvetica
+ 0.0pt
+ none
+ black
+ black
+
+
+ 8.0pt
+ 8.0pt
+ Helvetica
+ 0.5pt
+ solid
+ black
+
+
+ 7pt
+ 0.5pt
+ solid
+ black
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Amtliches Kennzeichen
+
+
+
+
+
+ Jahr
+
+
+
+
+
+
+
+
+
+
+
+
+ Dienstfahrzeug-Kostenblatt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ allgemeine Angaben
+
+
+
+
+
+
+ 1
+
+
+ Eigentümer
+
+
+
+
+
+ LAND
+
+
+ Halterdienststelle
+
+
+ TMIL
+
+
+ Nutzung
+
+
+ (Nah/Fern)
+
+
+
+
+
+
+
+
+
+ 2
+
+
+ Fahrzeugart und -typ
+
+
+
+
+
+
+
+
+
+
+ Kraftstoffart
+
+
+
+
+
+
+
+ Fahrzeug-Ident-Nr
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+ Erstzulassung
+
+
+ (Datum)
+
+
+
+
+
+
+
+ Übernahme
+
+
+
+
+
+
+
+ Aussonderung
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+ Anschaffungskosten
+
+
+ (EUR)
+
+
+
+
+
+
+
+ KFZ-Steuer
+
+
+ (EUR/Jahr)
+
+
+
+
+
+
+
+ Kosten GEZ
+
+
+ (EUR/Monat)
+
+
+
+
+
+
+
+
+
+
+ 5
+
+
+ überwiegend Selbstfahrer?
+
+
+
+
+
+
+
+ Leasingrate
+
+
+ (EUR/Monat)
+
+
+
+
+
+
+
+ Funk
+
+
+ (EUR/Monat)
+
+
+
+
+
+
+
+
+
+
+ 6
+
+
+ km-Stand Jahresanfang
+
+
+
+
+
+
+
+ km-Stand Jahresende
+
+
+
+
+
+
+
+ Auslastungsquote (p)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kfz-RL (Anlage 2) (c) 12.2015 TFM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Einsatz
+
+
+ Monat
+
+
+ Jan
+
+
+ Feb
+
+
+ Mrz
+
+
+ Apr
+
+
+ Mai
+
+
+ Jun
+
+
+ Jul
+
+
+ Aug
+
+
+ Sep
+
+
+ Okt
+
+
+ Nov
+
+
+ Dez
+
+
+ Summen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+