Is it possible to get the error text that is outside the StackTrace?

2024-10-25 09:53:02,293 [INFO][VPNM-INSIDE-CONTROL] Started downloading file from MinIO: ON_RISKSDNALMON_1_430_00_05_03_01.xsd
2024-10-25 09:53:04,144 [INFO][VPNM-INSIDE-CONTROL] File successfully downloaded from MinIO: ON_RISKSDNALMON_1_430_00_05_03_01.xsd
2024-10-25 09:53:04,764 [INFO][VPNM-INSIDE-CONTROL] Started downloading file from MinIO: ON_RISKSDNALMON_1_430_00_05_03_01.xslt
2024-10-25 09:53:04,794 [INFO][VPNM-INSIDE-CONTROL] File successfully loaded from MinIO: ON_RISKSDNALMON_1_430_00_05_03_01.xslt

The condition for the presence (absence) of the File/Document/Signatory/SvPred element was not met when the PrSubd element value was equal to "2".

Error at xsl:message on line 45 column 42 XTMM9000 Processing terminated by xsl:message at line 45 in In template rule with match="Signer" on line 40 of invoked by built-in template rule (text-only) In template rule with match="File" on line 30 of invoked by xsl:apply-templates (tail calls omitted) at #36 2024-10-25 09:53:42,086 [ERROR][VPNM-INSIDE-CONTROL] Error generating XML for RISKSDNALMON with parameters: idPeriod=2, idSignature=1, idDocument=ON_RISKSDNALMON_7700_7700_7710016640770701001_20241025_a4fc4f02-c330-4782-a625-f77a7989c290, idCompany=2 java.lang.RuntimeException: Errors when validating XML terminated by XSD: Processing d by xsl:message at line 45 in at 

Validation method:

    private void validateXmlBySchematronRules(String xml, InputStream xsltInputStream, CustomErrorHandler errorHandler, String xmlName) throws SaxonApiException, IOException {

            Processor processor = new Processor(false);
            XsltCompiler compiler = processor.newXsltCompiler();
            XsltExecutable xslt = compiler.compile(new StreamSource(xsltInputStream));
            XsltTransformer transformer = xslt.load();

            ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
            xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8));

            transformer.setParameter(new QName("fileName"), new XdmAtomicValue(xmlName));

            ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray());
            transformer.setSource(new StreamSource(xmlInputStream));
            XdmDestination chainResult = new XdmDestination();
            transformer.setDestination(chainResult);
            transformer.transform();


            List<String> errorList = new ArrayList<>();
            XdmNode rootNode = chainResult.getXdmNode();
            Iterator<XdmNode> childrenIterator = rootNode.children().iterator();
            if (childrenIterator.hasNext()) {
                XdmNode firstChild = childrenIterator.next();
                for (XdmNode node : firstChild.children()) {
                    if (!"failed-assert".equals(node.getNodeName().getLocalName())) continue;
                    String res = node.children().iterator().next().getStringValue();
                    errorList.add(formatString(res));
                }
            }

            if (!errorList.isEmpty()) {
                errorHandler.getErrors().addAll(errorList);
            }
    }

In debug mode I see only the main stack trace:

2024-10-25 09:53:42,086 [ERROR][VPNM-INSIDE-CONTROL] Error generating XML for RISKSDNALMON with parameters: idPeriod=2, idSignature=1, idDocument=ON_RISKSDNALMON_7700_7700_7710016640770701001_20241025_a4fc4f02-c330-4782-a625-f77a7989c290, idCompany=2 java.lang.RuntimeException: Errors while validating XML against XSD: Processing terminated by xsl:message at line 45 in etc.

But I need to take the error that is above this StackTrace:

The condition of presence (absence) of the File/Document/Signatory/SvPred element is not met with the value of the PrSubp element equal to “2”. Is there any way to do this?

To capture the error message that precedes the stack trace in your log and ensure that it is available for further processing, you need to modify how you’re handling exceptions in your validateXmlBySchematronRules method. Specifically, you need to enhance your error handling when processing XSLT transformations, particularly in relation to xsl:message.

Adjusting the XSLT Processing for Error Handling

Here’s a refined approach to handle errors during the XSLT transformation and capture the error messages effectively:

  1. Implement a Custom Error Listener: You can use a custom error listener to catch the messages generated by xsl:message. This way, you can store those messages in a list for later retrieval.
  2. Modify the Transformer: Set this custom error listener to the transformer before running the transformation.

Here’s how you can implement this:

Updated validateXmlBySchematronRules Method

import net.sf.saxon.s9api.*;
import java.io.*;

private void validateXmlBySchematronRules(String xml, InputStream xsltInputStream, CustomErrorHandler errorHandler, String xmlName) throws SaxonApiException, IOException {

    Processor processor = new Processor(false);
    XsltCompiler compiler = processor.newXsltCompiler();
    XsltExecutable xslt = compiler.compile(new StreamSource(xsltInputStream));
    XsltTransformer transformer = xslt.load();

    // Create a list to store error messages
    List<String> xslMessages = new ArrayList<>();

    // Set a custom error listener to capture xsl:message outputs
    transformer.setErrorListener(new ErrorListener() {
        @Override
        public void message(XdmNode node, boolean terminate) {
            // Store the message content
            xslMessages.add(node.getStringValue());
            if (terminate) {
                throw new RuntimeException("XSL message terminated processing: " + node.getStringValue());
            }
        }

        @Override
        public void warning(XdmNode node) {
            // Handle warnings if needed
        }

        @Override
        public void error(XdmNode node) {
            // Handle errors if needed
        }

        @Override
        public void fatalError(XdmNode node) {
            // Handle fatal errors if needed
        }
    });

    ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
    xmlOutputStream.write(xml.getBytes(StandardCharsets.UTF_8));

    transformer.setParameter(new QName("fileName"), new XdmAtomicValue(xmlName));

    ByteArrayInputStream xmlInputStream = new ByteArrayInputStream(xmlOutputStream.toByteArray());
    transformer.setSource(new StreamSource(xmlInputStream));
    XdmDestination chainResult = new XdmDestination();
    transformer.setDestination(chainResult);

    try {
        transformer.transform();
    } catch (SaxonApiException e) {
        // Log the custom error message(s)
        for (String message : xslMessages) {
            errorHandler.getErrors().add(formatString(message));
        }
        // Rethrow or handle exception as needed
        throw new RuntimeException("Errors while validating XML against XSD: " + e.getMessage(), e);
    }

    List<String> errorList = new ArrayList<>();
    XdmNode rootNode = chainResult.getXdmNode();
    Iterator<XdmNode> childrenIterator = rootNode.children().iterator();
    if (childrenIterator.hasNext()) {
        XdmNode firstChild = childrenIterator.next();
        for (XdmNode node : firstChild.children()) {
            if (!"failed-assert".equals(node.getNodeName().getLocalName())) continue;
            String res = node.children().iterator().next().getStringValue();
            errorList.add(formatString(res));
        }
    }

    if (!errorList.isEmpty()) {
        errorHandler.getErrors().addAll(errorList);
    }

    // Add captured XSL messages to the error handler if any
    if (!xslMessages.isEmpty()) {
        errorHandler.getErrors().addAll(xslMessages);
    }
}

Key Changes Made

  1. Custom Error Listener: Added a setErrorListener method to the transformer, allowing the capture of messages produced by xsl:message.
  2. Capture Messages: The messages are collected in the xslMessages list, which you can then add to your errorHandler.
  3. Exception Handling: If a termination occurs (due to terminate being true in xsl:message), you can throw a RuntimeException, but still allow the collection of messages to proceed.

Benefits

  • This approach allows you to capture specific xsl:message outputs that occur during transformation.
  • You can then decide how to handle and log these messages, ensuring you retain the important context needed for debugging.

By implementing this approach, you should be able to capture the error message about the condition not being met while maintaining a clear structure for your validation method.