Project

Profile

Help

Error "element found in wrong namespace" when using xml-to-json()

Added by Jeff Tennessen over 2 years ago

I'm working on a POC for a .NET Core 3.1 gRPC client that calls a Java gRPC server to do XSLT transformation using Saxon-EE. It's working well, except for XML to JSON conversions, which result in the following error:

Error at template on line 4 of <transformationname>:
  xml-to-json: element found in wrong namespace: Q{http://www.w3.org/2005/xpath-functions}map
net.sf.saxon.s9api.SaxonApiException: xml-to-json: element found in wrong namespace: Q{http://www.w3.org/2005/xpath-functions}map

I'm sure I'm doing something silly, so if anyone can point out what it is, I would greatly appreciate it. This is the protobuf:

syntax = "proto3";

option java_package = "<namespace>.messages";
option csharp_namespace = "Messages";

package <package>;

service Transformation {
    rpc Transform(TransformationRequest) returns (TransformationResponse) {}
}

message TransformationRequest {
    string stylesheetPath = 1;
    bytes input = 3;
}

message TransformationResponse {
    bytes transformed = 1;
}

This is the Java server code:

SaxonServer.java

package <namespace>.server;

import io.grpc.Server;
import io.grpc.ServerBuilder;

public class SaxonServer {
    public static void main(String[] args) {
        try {
            final SaxonServer saxonServer = new SaxonServer();

            saxonServer.start();
        }
        catch (Exception e) {
            System.err.println(e);
        }
    }

    private Server _server;

    private void start() throws Exception {
        _server = ServerBuilder.forPort(<port>)
                               .addService(new Transformation())
                               .build()
                               .start();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                SaxonServer.this.stop();
            }
        });

        _server.awaitTermination();
    }

    private void stop() {
        if (_server != null) {
            _server.shutdown();
        }
    }
}

Transformation.java

package <namespace>.server;

import com.google.protobuf.ByteString;
import io.grpc.stub.StreamObserver;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.s9api.*;
import org.xml.sax.InputSource;

import <namespace>.messages.*;

public class Transformation extends TransformationGrpc.TransformationImplBase {
    @Override
    public void transform(final Messages.TransformationRequest request, final StreamObserver<Messages.TransformationResponse> responseObserver) {
        try {
            final Processor proc = new Processor(true);
            final DocumentBuilder builder = proc.newDocumentBuilder();
            final StreamSource ss = new StreamSource(new File(request.getStylesheetPath()));
            final ArrayList<StaticError> err = new ArrayList<StaticError>();
            final XsltCompiler cmp = proc.newXsltCompiler();
            final SAXSource sxs = new SAXSource(new InputSource(new ByteArrayInputStream(request.getInput().toByteArray())));
            final StringWriter result = new StringWriter(2048);
    
            cmp.setErrorList(err);
            cmp.compile(ss).load30().applyTemplates(builder.build(sxs), proc.newSerializer(result));
    
            final StringBuffer sb = result.getBuffer();
            final Messages.TransformationResponse resp = 
                Messages.TransformationResponse
                        .newBuilder()
                        .setTransformed(ByteString.copyFrom(sb.toString().getBytes()))
                        .build();
    
            responseObserver.onNext(resp);
            responseObserver.onCompleted();
        } catch (SaxonApiException e) {
            System.err.println(e);
        }
    }
}

This is the stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:output method="text"/>
  <xsl:template match="/">
    <xsl:value-of select="xml-to-json(.)"/>
  </xsl:template>
</xsl:stylesheet>

This is the C# client code:

using System;
using System.Threading.Tasks;
using Google.Protobuf;
using Grpc.Core;
using Messages;

namespace GrpcClientTest
{
    class Program
    {
        static void Main(string[] args)
        {
            ByteString input = ByteString.CopyFromUtf8(args[0]);
            string result = TransformAsync(args[1], input).Result;
            Console.WriteLine(result);
            Console.ReadLine();
        }

        private static Channel _channel = new Channel(Environment.MachineName, <port>, ChannelCredentials.Insecure);
        private static Transformation.TransformationClient _client = new Transformation.TransformationClient(_channel);

        public static async Task<string> TransformAsync(string xsltPath, ByteString xml)
        {
            try
            {
                TransformationResponse response = await _client.TransformAsync(new TransformationRequest
                {
                    StylesheetPath = xsltPath,
                    Input = xml
                });
                return response.Transformed.ToStringUtf8();
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }
    }
}

And this is the input XML:

<map xmlns="http://www.w3.org/2005/xpath-functions">
  <string key="foo">bar</string>
</map>

I am, of course, expecting successful output like this:

{"foo":"bar"}

Thanks!


Replies (3)

Please register to reply

RE: Error "element found in wrong namespace" when using xml-to-json() - Added by Michael Kay over 2 years ago

Very strange indeed. Your stylesheet of course works fine against that XML document when run from the command line, so there's something odd going on.

The diagnostic makes very little sense. It comes from code that does this:

        if (!elemName.hasURI(NamespaceConstant.FN)) {
            throw new XPathException("xml-to-json: element found in wrong namespace: " +
                                             elemName.getStructuredQName().getEQName(), ERR_INPUT);
        }

and the EQName displayed appears to suggest that the URI is the correct URI (NamespaceConstant.FN).

Could I ask what Saxon version you are using? (I don't expect it makes a difference, but it's nice to know.)

RE: Error "element found in wrong namespace" when using xml-to-json() - Added by Michael Kay over 2 years ago

There was a draft of the XSLT 3.0 spec in which the XML was expected to be in namespace "http://www.w3.org/2013/XSL/json", and that's how the function was implemented in 9.6; it changed to the final namespace in 9.7.

So my suspicion is that you are running Saxon 9.6.

RE: Error "element found in wrong namespace" when using xml-to-json() - Added by Jeff Tennessen over 2 years ago

You are correct, we're using 9.6.0.6 (should've mentioned that in the question). I know we're way behind, but the company's procurement process makes upgrading certain components extremely painful. This is probably the straw that broke the camel's back, though.

I've verified that using "http://www.w3.org/2013/XSL/json" as the namespace resolves the error. I very much appreciate your help!

    (1-3/3)

    Please register to reply