From 6fcf706d96c315b5a2bafff4377b072abcf931af Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 28 Dec 2025 15:50:03 +0100 Subject: [PATCH] Fix: Verwende Saxon s9api statt Transform.main() um System.exit() zu vermeiden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Transform.main() ruft System.exit() auf, was den gesamten Worker-Prozess beendet Lösung: Umstellung auf Saxon s9api (programmatische API): - Verwendet Processor, XsltCompiler, XsltExecutable, Xslt30Transformer - Wirft SaxonApiException statt System.exit() aufzurufen - Processor wird einmalig erstellt und wiederverwendet (Performance!) - Parameter-Handling mit QName und XdmValue - Serializer für Ausgabe statt Kommandozeilen-Args Dies sollte die Worker-Crashes vollständig beheben. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/saxon_pool.py | 93 ++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/src/saxon_pool.py b/src/saxon_pool.py index 64f4d3a..4136328 100644 --- a/src/saxon_pool.py +++ b/src/saxon_pool.py @@ -17,7 +17,8 @@ logger = logging.getLogger(__name__) # Java-Worker-Code (wird zur Laufzeit kompiliert) SAXON_WORKER_JAVA = """ -import net.sf.saxon.Transform; +import net.sf.saxon.s9api.*; +import javax.xml.transform.stream.StreamSource; import java.io.*; import java.util.*; @@ -26,7 +27,10 @@ public class SaxonWorker { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String line; - System.err.println("SaxonWorker started and ready"); + // Create Saxon Processor (reusable) + Processor processor = new Processor(false); + + System.err.println("SaxonWorker started and ready (using s9api)"); System.err.flush(); try { @@ -58,62 +62,67 @@ public class SaxonWorker { String xslStylesheet = parts[1]; String outputFo = parts[2]; - System.err.println("DEBUG: Building Saxon args..."); + System.err.println("DEBUG: Files - XML: " + sourceXml); + System.err.println("DEBUG: Files - XSL: " + xslStylesheet); + System.err.println("DEBUG: Files - OUT: " + outputFo); System.err.flush(); - // Build Saxon arguments - List saxonArgs = new ArrayList<>(); - saxonArgs.add("-s:" + sourceXml); - saxonArgs.add("-xsl:" + xslStylesheet); - saxonArgs.add("-o:" + outputFo); - - // Add parameters if present + // Parse parameters if present + Map xsltParams = new HashMap<>(); if (parts.length > 3 && !parts[3].isEmpty()) { String[] params = parts[3].split("\\\\|\\\\|\\\\|"); for (String param : params) { - if (!param.isEmpty()) { - saxonArgs.add(param); + if (!param.isEmpty() && param.contains("=")) { + String[] kv = param.split("=", 2); + xsltParams.put(kv[0], kv[1]); } } } - - System.err.println("DEBUG: Running Saxon transformation..."); + System.err.println("DEBUG: Parameters: " + xsltParams.size()); System.err.flush(); - // Redirect Saxon output to stderr to avoid polluting stdout - PrintStream oldOut = System.out; - PrintStream oldErr = System.err; - ByteArrayOutputStream saxonOut = new ByteArrayOutputStream(); - ByteArrayOutputStream saxonErr = new ByteArrayOutputStream(); + System.err.println("DEBUG: Compiling stylesheet..."); + System.err.flush(); - try { - System.setOut(new PrintStream(saxonOut)); - System.setErr(new PrintStream(saxonErr)); + // Compile stylesheet (s9api) + XsltCompiler compiler = processor.newXsltCompiler(); + XsltExecutable executable = compiler.compile(new StreamSource(new File(xslStylesheet))); - // Run Saxon transformation - Transform.main(saxonArgs.toArray(new String[0])); + System.err.println("DEBUG: Creating transformer..."); + System.err.flush(); - // Restore streams - System.setOut(oldOut); - System.setErr(oldErr); + // Create transformer + Xslt30Transformer transformer = executable.load30(); - oldErr.println("DEBUG: Saxon transformation completed"); - oldErr.flush(); - - // Send success response - System.out.println("OK"); - System.out.flush(); - - } catch (Exception e) { - System.setOut(oldOut); - System.setErr(oldErr); - oldErr.println("DEBUG: Saxon exception: " + e.getClass().getName()); - oldErr.flush(); - e.printStackTrace(oldErr); - System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName())); - System.out.flush(); + // Set parameters + if (!xsltParams.isEmpty()) { + Map params = new HashMap<>(); + for (Map.Entry param : xsltParams.entrySet()) { + params.put(new QName(param.getKey()), XdmValue.makeValue(param.getValue())); + } + transformer.setStylesheetParameters(params); } + System.err.println("DEBUG: Running transformation..."); + System.err.flush(); + + // Run transformation + Serializer serializer = processor.newSerializer(new File(outputFo)); + transformer.transform(new StreamSource(new File(sourceXml)), serializer); + + System.err.println("DEBUG: Transformation completed successfully"); + System.err.flush(); + + // Send success response + System.out.println("OK"); + System.out.flush(); + + } catch (SaxonApiException e) { + System.err.println("DEBUG: Saxon API exception: " + e.getClass().getName()); + System.err.flush(); + e.printStackTrace(System.err); + System.out.println("ERROR: " + (e.getMessage() != null ? e.getMessage() : e.getClass().getName())); + System.out.flush(); } catch (Exception e) { System.err.println("DEBUG: Job processing exception: " + e.getClass().getName()); System.err.flush();