Search code examples
c#.netxmlxsltsaxon

How do I retrieve error details when Saxon XSLT transformation fails?


I am using Saxon 9 HE 9.7.0.7 for .NET. Typically, when I run XsltTransformer.Run, the DomDestination.XmlDocument property will be populated. However, with some documents, that property will be null. When the property is null, I am assuming that some kind of error was encountered, but no exceptions are thrown, and I'm not seeing any errors on the console. How can I retrieve details regarding why the transformation failed?

For one such example document, I tried the transform from the command line and it completed without any issue.

Here is some example code. The destination.XmlDocument property on the last line will sometimes be null.

        // Compile stylesheet
        var processor = new Processor();
        var compiler = processor.NewXsltCompiler();
        var executable = compiler.Compile(new Uri(xsltFilePath));
        var declaredArgs = executable.GetGlobalParameters();

        // Do transformation to a destination
        var destination = new DomDestination();
        using (var inputStream = new MemoryStream())
        {
            xml.Save(inputStream);
            inputStream.Position = 0;
            var transformer = executable.Load();
            transformer.SetInputStream(inputStream, new Uri(inputXmlFileInfo.DirectoryName));
            foreach (var arg in args)
            {
                var matchingArgDeclaration = declaredArgs.FirstOrDefault(a => a.Key.LocalName.ToLower() == arg.Key.ToLower());
                if (matchingArgDeclaration.Key == null)
                {
                    transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(arg.Value));
                }
                else
                {
                    // try to load up the specific parameter type
                    // list is based on http://www.saxonica.com/documentation/#!dotnetdoc/Saxon.Api/XdmAtomicValue
                    XdmItemType argType = matchingArgDeclaration.Value.getDeclaredItemType();
                    var argTypeName = "";
                    if (argType != null &&
                        argType is XdmAtomicType)
                        argTypeName = ((XdmAtomicType)argType).Name.LocalName;
                    switch (argTypeName.ToLower())
                    {
                        case "boolean":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(Convert.ToBoolean(arg.Value)));
                            break;

                        case "integer":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(Convert.ToInt32(arg.Value)));
                            break;

                        case "decimal":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(Convert.ToDecimal(arg.Value)));
                            break;

                        case "float":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(Convert.ToSingle(arg.Value)));
                            break;

                        case "double":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(Convert.ToDouble(arg.Value)));
                            break;

                        case "anyuri":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(new Uri(arg.Value)));
                            break;

                        case "qname":
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(new QName(arg.Value)));
                            break;

                        default:
                            transformer.SetParameter(new QName(arg.Key), new XdmAtomicValue(((arg.Value))));
                            break;
                    }
                }
            }

            transformer.Run(destination);
        }

        // Save result to a file (or whatever else you wanna do)
        destination.XmlDocument.Save(outputFileName);

Solution

  • There are two kinds of error: static errors and dynamic errors.

    Static errors (for example, syntax errors, or use of an undeclared variable or function) are added to the ErrorList property of the XsltCompiler. The Compile() method will throw an exception, and you should then check the details in the ErrorList for detailed diagnostics.

    Dynamic errors (for example divide by zero) result in the XsltTransformer.Run() method throwing an exception of class Saxon.Api.DynamicError.