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:
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.
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
Custom Error Listener: Added a setErrorListener method to the transformer, allowing the capture of messages produced by xsl:message.
Capture Messages: The messages are collected in the xslMessages list, which you can then add to your errorHandler.
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.