I have build an app that validates and xml with a schematron.
Here is the code:
import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ValidateSchema {
public static void main(String[] args) {
try {
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable xslt = compiler.compile(new StreamSource(
new File("target/example.xsl")
));
XsltTransformer transformer = xslt.load();
transformer.setSource(new StreamSource(new File("example.xml")));
XdmDestination chainResult = new XdmDestination();
transformer.setDestination(chainResult);
transformer.transform();
List<String> errorList = new ArrayList<>();
XdmNode rootnode = chainResult.getXdmNode();
for (XdmNode node : rootnode.children().iterator().next().children()) {
if(!"failed-assert".equals(node.getNodeName().getLocalName())) continue;
String res = node.children().iterator().next().getStringValue();
errorList.add(trim(res));
}
for (String s : errorList) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String trim(String s) {
s = s.replaceAll("\n", "").replaceAll("\t", " ");
while (s.indexOf(" ") != -1) {
s = s.replaceAll(" ", " ");
}
return s.trim();
}
}
When I try to run the application it gives me the error: java.lang.NullPointerException at ValidateSchema.main(ValidateSchema.java:27) which is this line of code:
if(!"failed-assert".equals(node.getNodeName().getLocalName())) continue;
It is the first time I am building something like this and I am wondering how can I fix this. Thanks in advance
CodePudding user response:
Your iteration
for (XdmNode node : rootnode.children().iterator().next().children())
is probably delivering nodes (such as text nodes) that have no name, so
node.getNodeName() returns null, so
node.getNodeName().getLocalName() fails with an NPE.
You can restrict children() to return elements only using children(Predicates.isElement()).
Alternatively change the loop to
for (XdmNode node : rootnode.children().iterator().next().children("failed-assert")) {
String res = node.children().iterator().next().getStringValue();
errorList.add(trim(res));
}
or more concisely
for (XdmNode node : rootnode.select(Steps.path(*, "failed-assert")) {
errorList.add(node.select(Steps.child()).first().getStringValue());
}
CodePudding user response:
I would consider to use XPath to select the text messages e.g. if you select e.g. /*/*:failed-assert or better /*/*:failed-assert => string-join(codepoints-to-string(10)) with XPath on the rootnode of the validation result you get a list of all failed assert messages.
Might be cleaner to set up/declare the namespace for xmlns:svrl="http://purl.oclc.org/dsdl/svrl" and use //svrl:failed-assert => string-join(codepoints-to-string(10)) but both examples should get you on the way to just use XPath to extract error messages.
On the Java side that would be used as
XdmItem result = processor.newXPathCompiler.evaluateSingle("/*/*:failed-assert => string-join(codepoints-to-string(10))", rootnode);
and then you can output result.getStringValue().
