Bug #5102
closedSystem.ArgumentNullException from message listener (unknown location URI?)
100%
Description
We're currently in the process of updating to Saxon-HE 10.6N and one of our stylesheets started to blow up for no apparent reason. Deep down we see this one:
System.ArgumentNullException
HResult=0x80004003
Message=Value cannot be null.
Parameter name: uriString
Source=System
StackTrace:
at System.Uri..ctor(String uriString)
This exception was originally thrown at this call stack:
System.Uri.Uri(string)
...which is at:
System.dll!System.Uri.Uri(string uriString) Unknown
saxon-he-api-10.6.dll!Saxon.Api.MessageListenerProxy2.message(net.sf.saxon.s9api.XdmNode xn, net.sf.saxon.s9api.QName qn, bool b, javax.xml.transform.SourceLocator sl) Unknown
saxon-he-10.6.dll!net.sf.saxon.s9api.MessageListener2Proxy.write(net.sf.saxon.om.Item value) Unknown
saxon-he-10.6.dll!net.sf.saxon.event.SequenceWriter.append(net.sf.saxon.om.Item item, net.sf.saxon.s9api.Location locationId, int copyNamespaces) Unknown
saxon-he-10.6.dll!net.sf.saxon.s9api.MessageListener2Proxy.append(net.sf.saxon.om.Item value, net.sf.saxon.s9api.Location value, int value) Unknown
saxon-he-10.6.dll!net.sf.saxon.event.SequenceWriter.endDocument() Unknown
saxon-he-10.6.dll!net.sf.saxon.event.TreeReceiver.endDocument() Unknown
saxon-he-10.6.dll!net.sf.saxon.event.ProxyReceiver.endDocument() Unknown
saxon-he-10.6.dll!net.sf.saxon.event.ComplexContentOutputter.endDocument() Unknown
saxon-he-10.6.dll!net.sf.saxon.expr.instruct.Message.processLeavingTail(net.sf.saxon.event.Outputter output, net.sf.saxon.expr.XPathContext context) Unknown
saxon-he-10.6.dll!net.sf.saxon.expr.instruct.Block.processLeavingTail(net.sf.saxon.event.Outputter output, net.sf.saxon.expr.XPathContext context) Unknown
saxon-he-10.6.dll!net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(net.sf.saxon.event.Outputter output, net.sf.saxon.expr.XPathContext context) Unknown
saxon-he-10.6.dll!net.sf.saxon.trans.Mode.applyTemplates(net.sf.saxon.expr.instruct.ParameterSet parameters, net.sf.saxon.expr.instruct.ParameterSet tunnelParameters, net.sf.saxon.om.NodeInfo separator, net.sf.saxon.event.Outputter output, net.sf.saxon.expr.XPathContextMajor context, net.sf.saxon.s9api.Location locationId) Unknown
saxon-he-10.6.dll!net.sf.saxon.trans.XsltController.applyTemplates(net.sf.saxon.om.Sequence source, net.sf.saxon.event.Receiver out) Unknown
saxon-he-10.6.dll!net.sf.saxon.s9api.AbstractXsltTransformer.applyTemplatesToSource(javax.xml.transform.Source value, net.sf.saxon.event.Receiver value) Unknown
saxon-he-10.6.dll!net.sf.saxon.s9api.XsltTransformer.transform() Unknown
saxon-he-api-10.6.dll!Saxon.Api.XsltTransformer.Run(Saxon.Api.XmlDestination destination) Unknown
...and is followed up by this when ignoring exceptions that are caught internally:
java.lang.RuntimeException
HResult=0x80131500
Message=Internal error evaluating template rule in module file:///D:/_dev/SaxonMLP2NullPointer/bin/Debug/SaxonMLP2NullPointer.exe
Source=saxon-he-10.6
StackTrace:
at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(Outputter output, XPathContext context)
at net.sf.saxon.trans.Mode.applyTemplates(ParameterSet parameters, ParameterSet tunnelParameters, NodeInfo separator, Outputter output, XPathContextMajor context, Location locationId)
at net.sf.saxon.trans.XsltController.applyTemplates(Sequence source, Receiver out)
at net.sf.saxon.s9api.AbstractXsltTransformer.applyTemplatesToSource(Source , Receiver )
at net.sf.saxon.s9api.XsltTransformer.transform()
at Saxon.Api.XsltTransformer.Run(XmlDestination destination)
at SaxonMLP2NullPointer.Program.Main(String[] args) in D:\_dev\SaxonMLP2NullPointer\Program.cs:line 39
Inner Exception 1:
NullPointerException:
It appears that in those cases, SourceLocator sl
inside MessagListenerProxy2.message
is net.sf.saxon.expr.parser.Loc@1029822 { columnNumber: -1, lineNumber: -1, systemId: null }
and fails when attempting to set location.BaseUri = new Uri(sl.getSystemId());
due to sl.getSystemId()
returning null
.
I managed to create a stripped down example that still causes the issue, and it appears to be related to having both a custom MessageListener2
on the XsltTransformer
, as well as writing a <xsl:message>
that contains either <xsl:value-of/>
or <xsl:sequence/>
to produce the message itself from a non-xs:string
source (that is: no select
attribute, any expression that is not of type xs:string
or uses any function to produce a xs:string
; including a call to concat()
).
Here's the (minimalistic) source:
internal class Program
{
private static void Main(string[] args)
{
var xslt = XDocument.Parse(@"
<stylesheet xmlns='http://www.w3.org/1999/XSL/Transform' version='3.0'>
<template match='/'>
<!-- this message causes an error when MessageListener2 is used -->
<message><value-of select='local-name()'/></message>
<result xmlns=''/>
</template>
</stylesheet>");
var input = xslt; // does not matter for this test.
var output = new XDocument();
var processor = new Processor();
using (var xsltReader = xslt.CreateReader())
using (var inputReader = input.CreateReader())
using (var outputWriter = output.CreateWriter())
{
var compiler = processor.NewXsltCompiler();
compiler.BaseUri = new Uri(typeof(Program).Assembly.Location);
var xsltExecutable = compiler.Compile(xsltReader);
var transformer = xsltExecutable.Load();
var builder = processor.NewDocumentBuilder();
transformer.InitialContextNode = builder.Build(inputReader);
// comment this out to prevent the issue
transformer.MessageListener2 = new TestMessageListener();
var destination = new TextWriterDestination(outputWriter) { CloseAfterUse = true };
transformer.Run(destination);
}
}
private sealed class TestMessageListener : IMessageListener2
{
public void Message(XdmNode content, QName errorCode, bool terminate, IXmlLocation location) { }
}
}
The code will work when:
-
transformer.MessageListener2
is not set by the code (ortransformer.MessageListener
if theerrorCode
parameter is not neede by the listener) - The contents of
<message>
is plain text (such as<message>test</message>
) - The contents of
<message>
is a string variable (such as<variable name="message" select="'test'"/><message><value-of select="$message"/></message>
)
The code will not work when:
- The contents of
<message>
is produced by a function call (such as<message><value-of select="concat('Message here: ', $message)"/></message>
) - The contents of
<message>
is not of typexs:string
(such as<variable name="message" select="42"/><message><value-of select="$message"/></message>
) - The contents of
<message>
use the concatenation operator (such as<message><value-of select="Message here: " || $message"/></message>
- which might be the same as the first case though)
For obvious reasons, we can't simply not add the MessageListener2
because we want to capture <xsl:message>
including the errorCode
. And the same thing happens if we revert back to MessageListener
, except that it happens in MessageListenerProxy
instead of MessageListenerProxy2
in that case.
This is using the currently most recent NuGet package with version 10.6.0 on .NET Framework 4.8
Please register to edit this issue