Project

Profile

Help

Performing HTTP POST from XSLT using either Java or .NET calls from Saxon

Added by Matt Klem 4 days ago

My apologies for the cross-post. I think I had this in the wrong forum. (Mods can feel free to delete the one in the "Open Discussion")

I was directed to try and ask about this request via my original post on Stack Overflow. You can find that post here: https://stackoverflow.com/questions/79148922/looking-to-perform-http-post-from-xslt-using-either-java-or-net-calls-from-saxo/79155315

I am trying to see if it is possible to perform an HTTP POST operation from an XSLT sheet, using the .NET extensions within Saxon. I cannot add any additional libraries (including the EXPath HTTP-client ones) to my environment because Saxon is rolled into a custom 3rd party application.

I am currently using Saxon EE v10.6 through a proprietary third party tool. The company I work for does not own this tool, but we use it daily as part of various services engagement with customers. This tool uses Saxon to perform XSLT transformations, primarily taking XML and converting it into Office Open XML to generate native MS Office documents.

Historically, when we've hit limits from this 3rd party app, we've written custom .NET DLLs that contain our own code, and invoked them from an XSLT stylesheet using the "clitype" qualifier on a namespace. This has worked extremely well and allowed us to extend functionality as needed.

However, we're now in a situation where the 3rd party use of Saxon is now executed within a cloud environment space. As a result, we can no longer add custom DLLs that our XSLT code can refer to. We can only use Saxon and any of the already-included libraries that come with it. We've tested the ability to invoke .NET from the cloud version with things like xmlns:test="clitype:System.Math" and test:Sqrt(64), etc so we know the cloud version still lets us call .NET. We just need to figure out how to do it for an HTTP POST.

Since I know we can refer to .NET namespaces/classes through clitype, I'm trying to see if there's anyway to replicate this type of .NET code through a stylesheet:

var url = "https://httpbin.org/post";
var client = new HttpClient;
var content = new StringContent(payload, System.Text.Encoding.UTF8,"application/json");
var response = await client.PostAsync(url, content);

And yes, I know this is a barebones example, but I just want to show something close to what I want to do. I've used a variation of that .NET code in Windows Workflow Foundation to successfull pass a JSON payload to an API endpoint (Power Automate specifically).

On the StackOverflow post, someone gave me a sheet with the logic worked out using Java but my third party tool rejects it with a weird meaningless error.

I was hoping someone here might have any suggestions on how to craft the XSLT to use .NET methods for invoking an HTTP post.

Any thoughts or suggestions are greatly appreciated. Thanks.

Matt


Replies (11)

Please register to reply

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Michael Kay 4 days ago

Doing this without any custom "glue" code is certainly a bit challenging, especially because of the asynchrony.

I don't really know the .NET asynchronous API well enough to be sure how to achieve this, but in principle, if you can achieve the effect of "await" by applying a series of method calls to the Task<HttpResponseMessage> returned by the PostAsync method, then it ought to be possible to replicate those calls as XPath extension function calls.

What you can't do is use "await" explicitly.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 3 days ago

Mike,

what is the magic needed in Saxon EE .NET to get a reflexive constructor with clitype to work?

My attempts fail e.g. the stylesheet

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  xmlns:HttpClient="clitype:System.Net.Http.HttpClient"
  xmlns:StringContent="clitype:System.Net.Http.StringContent"
  xmlns:HttpResponseMessage="clitype:System.Net.Http.HttpResponseMessage"
  xmlns:HttpContent="clitype:System.Net.Http.HttpContent"
  xmlns:Task="clitype:System.Threading.Tasks.Task"
  xmlns:Encoding="clitype:System.Text.Encoding"
  exclude-result-prefixes="#all">

  <xsl:param name="staticHttpClient" select="HttpClient:new()"/>

  <xsl:param name="json-string" as="xs:string">{ "name" : "foo", "data" : [1, 2, 3] }</xsl:param>

  <xsl:function name="mf:HttpPost" as="xs:string" visibility="public" new-each-time="yes">
    <xsl:param name="uri" as="xs:string"/>
    <xsl:param name="content" as="xs:string"/>
    <xsl:param name="content-type" as="xs:string"/>
    <xsl:variable name="body" select="StringContent:new($content, Encoding:UTF8(), $content-type)"/>
    <xsl:variable name="response" select="HttpClient:PostAsync($staticHttpClient, $uri, $body)"/>
    <xsl:message select="Task:Wait($response)"/>
    <xsl:variable name="result" select="Task:Result($response)"/>
    <xsl:message select="HttpResponseMessage:EnsureSuccessStatusCode($result)"/>
    <xsl:variable name="resultContent" select="HttpResponseMessage:Content($result)"/>
    <xsl:variable name="stringTask" select="HttpContent:ReadAsStringAsync($resultContent)"/>
    <xsl:message select="Task:Wait($stringTask)"/>
    <xsl:variable name="resultString" select="Task:Result($stringTask)"/>
    <xsl:message select="Task:Dispose($response)"/>
    <xsl:message select="HttpResponseMessage:Dispose($result)"/>
    <xsl:message select="Task:Dispose($resultContent)"/>
    <xsl:message select="Task:Dispose($stringTask)"/>

    <xsl:sequence select="$resultString"/>
  </xsl:function>

  <xsl:output method="text"/>

  <xsl:template match="/" name="main">
    <xsl:value-of select="mf:HttpPost('https://httpbin.org/post', $json-string, 'application/json')"/>
    <xsl:text>&#10;Run with </xsl:text>
    <xsl:value-of select="system-property('xsl:product-name'), system-property('xsl:product-version'), 'at', current-dateTime()" separator=" "/>
  </xsl:template>

</xsl:stylesheet>

when run with Saxon EE 10.9 .NET Transform.exe -it:main -t -TJ does not even manage to instantiate the HttpClient:

Saxon-EE 10.9N from Saxonica
.NET 4.0.30319.42000 on Microsoft Windows NT 6.2.9200.0
Using license serial number ....
URIResolver.resolve href="file:/C:/Users/marti/OneDrive/Documents/xslt/blog-xslt-3-by-example/SaxonEE10Net/./http-post-request-test2.xsl" base="null"
Looking for function Q{clitype:System.Net.Http.HttpClient}new#0
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Trying net.sf.saxon.style.StylesheetFunctionLibrary
Trying net.sf.saxon.functions.FunctionLibraryList
Looking for function Q{clitype:System.Net.Http.HttpClient}new#0
Trying com.saxonica.ee.extfn.VendorFunctionSetEE
Trying net.sf.saxon.functions.MathFunctionSet
Trying net.sf.saxon.ma.map.MapFunctionSet
Trying net.sf.saxon.ma.arrays.ArrayFunctionSet
Trying net.sf.saxon.functions.registry.ExsltCommonFunctionSet
Trying com.saxonica.functions.extfn.EXPathFileFunctionSet
Trying net.sf.saxon.functions.registry.OnDemandFunctionSet
Function Q{clitype:System.Net.Http.HttpClient}new not found!
Trying net.sf.saxon.functions.registry.ConstructorFunctionLibrary
Trying net.sf.saxon.query.XQueryFunctionLibrary
Trying net.sf.saxon.functions.IntegratedFunctionLibrary
Trying com.saxonica.config.DotNetExtensionLibrary
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Trying com.saxonica.config.JavaExtensionLibrary
Trying net.sf.saxon.style.StylesheetFunctionLibrary
Function Q{clitype:System.Net.Http.HttpClient}new not found!
Looking for function Q{clitype:System.Net.Http.HttpClient}new#0
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Trying net.sf.saxon.style.StylesheetFunctionLibrary
Trying net.sf.saxon.functions.FunctionLibraryList
Looking for function Q{clitype:System.Net.Http.HttpClient}new#0
Trying com.saxonica.ee.extfn.VendorFunctionSetEE
Trying net.sf.saxon.functions.MathFunctionSet
Trying net.sf.saxon.ma.map.MapFunctionSet
Trying net.sf.saxon.ma.arrays.ArrayFunctionSet
Trying net.sf.saxon.functions.registry.ExsltCommonFunctionSet
Trying com.saxonica.functions.extfn.EXPathFileFunctionSet
Trying net.sf.saxon.functions.registry.OnDemandFunctionSet
Function Q{clitype:System.Net.Http.HttpClient}new not found!
Trying net.sf.saxon.functions.registry.ConstructorFunctionLibrary
Trying net.sf.saxon.query.XQueryFunctionLibrary
Trying net.sf.saxon.functions.IntegratedFunctionLibrary
Trying com.saxonica.config.DotNetExtensionLibrary
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Trying com.saxonica.config.JavaExtensionLibrary
Trying net.sf.saxon.style.StylesheetFunctionLibrary
Function Q{clitype:System.Net.Http.HttpClient}new not found!
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Failed to load type System.Net.Http.HttpClient: Der Typ "System.Net.Http.HttpClient" in der Assembly "saxon-ee-10.9, Version=10.9.0.0, Culture=neutral, PublicKeyToken=e1fdd002d5083fe6" konnte nicht geladen werden.
Error in {HttpClient:new()} at char 0 in xsl:param/@select on line 14 column 65 of http-post-request-test2.xsl:
  XPST0017  Cannot find a 0-argument function named
  Q{clitype:System.Net.Http.HttpClient}new().

For the class Encoding the profile shows it looks at some place for Looking for method UTF8 in .NET type System.Text.Encoding but it seems to fail to do a similar search of e.g. Looking for constructor in .NET type System.Net.Http.HttpClient.

There is not really another engine to compare but embedded similar .NET code in XmlPrime 5 runs fine e.g. the following code

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="#all">

  <xsl:param name="json-string" as="xs:string">{ "name" : "foo", "data" : [1, 2, 3] }</xsl:param>

  <msxsl:script language="cs" implements-prefix="mf">
    <msxsl:assembly name="System.Net.Http"/>
    <msxsl:using namespace="System.Net.Http"/>
    <msxsl:using namespace="System.Text"/>
    
    static readonly HttpClient httpClient = new HttpClient();

        public static string HttpPost(string uri, string content, string contentType)
        {
            var body = new StringContent(content, Encoding.UTF8, contentType);

            var response = httpClient.PostAsync(uri, body);

            response.Wait();

            var result = response.Result;

            result.EnsureSuccessStatusCode();

            var resultContent = result.Content;

            var stringTask = resultContent.ReadAsStringAsync();

            stringTask.Wait();

            var resultString = stringTask.Result;

            response.Dispose();

            result.Dispose();

            resultContent.Dispose();

            stringTask.Dispose();

            return resultString;

        }
  </msxsl:script>


  <xsl:output method="text"/>

  <xsl:template match="/" name="main">
    <xsl:value-of select="mf:HttpPost('https://httpbin.org/post', $json-string, 'application/json')"/>
    <xsl:text>&#10;Run with </xsl:text>
    <xsl:value-of select="system-property('xsl:product-name'), system-property('xsl:product-version'), 'at', current-dateTime()" separator=" "/>
  </xsl:template>

</xsl:stylesheet>

there is processed and outputs e.g.

{
  "args": {},
  "data": "{ \"name\" : \"foo\", \"data\" : [1, 2, 3] }",
  "files": {},
  "form": {},
  "headers": {
    "Content-Length": "38",
    "Content-Type": "application/json; charset=utf-8",
    "Host": "httpbin.org",
    "X-Amzn-Trace-Id": "Root=1-67389bb8-680c6725188a768c42519a53"
  },
  "json": {
    "data": [
      1,
      2,
      3
    ],
    "name": "foo"
  },
  "origin": "176.199.255.78",
  "url": "https://httpbin.org/post"
}

Run with XmlPrime 5.0.6.25607 at 2024-11-16T14:18:48.7573939+01:00

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 1 day ago

It seems I have found a way to find the assembly, using e.g. xmlns:HttpClient="clitype:System.Net.Http.HttpClient?partialname=System.Net.Http" shows me traces like

Assembly System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a successfully loaded
Assembly codebase (GAC): file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Net.Http/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Net.Http.dll
Looking for method new in .NET type System.Net.Http.HttpClient
Number of actual arguments = 0
Looking for a constructor

so that part seems to be solved.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Michael Kay 1 day ago

Good you're making progress, please keep us informed.

I'm afraid I've always found dynamic loading in .NET to be a bit of a nightmare, which is why we've tried to reduce or eliminate the need for it in SaxonCS.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 1 day ago

As the HttpClient code I have used various generic classes/type parameters like Task<T> and I couldn't find a way to declare them properly with clitype I have tried to use the deprecated WebClient class instead, simplest code I have come up with is e.g.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  xmlns:WebClient="clitype:System.Net.WebClient?partialname=System.Net"
  exclude-result-prefixes="#all">

  <xsl:param name="staticWebClient" select="WebClient:new()"/>

  <xsl:param name="json-string" as="xs:string">{ "name" : "foo", "data" : [1, 2, 3] }</xsl:param>

  <xsl:param name="uri" as="xs:string" select="'https://httpbin.org/post'"/>

  <xsl:output method="text"/>

  <xsl:template match="/" name="main">
    <xsl:variable name="response" select="WebClient:UploadString($staticWebClient, $uri, $json-string)"/>
    <xsl:sequence select="$response"/>
    <xsl:text>&#10;Run with </xsl:text>
    <xsl:value-of select="system-property('xsl:product-name'), system-property('xsl:product-version'), 'at', current-dateTime()" separator=" "/>
  </xsl:template>

</xsl:stylesheet>

on running this through Saxon EE 10.9 .NET Transform.exe unfortunately it throws an error:

Saxon-EE 10.9N from Saxonica
.NET 4.0.30319.42000 on Microsoft Windows NT 6.2.9200.0
Using license serial number ...
URIResolver.resolve href="file:/C:/Users/marti/OneDrive/Documents/xslt/blog-xslt-3-by-example/SaxonEE10Net/./http-post-web-client-test1.xsl" base="null"
** Failed to load type net.sf.saxon.om.DocumentInfo
java.lang.UnsupportedOperationException
        at com.saxonica.expr.DotNetExtensionFunctionCall.copy(DotNetExtensionFunctionCall.java:188)
        at net.sf.saxon.expr.LetExpression.copy(LetExpression.java:710)
        at net.sf.saxon.style.XSLTemplate.compileTemplateRule(XSLTemplate.java:732)
        at net.sf.saxon.style.XSLTemplate.compileDeclaration(XSLTemplate.java:650)
        at net.sf.saxon.style.PrincipalStylesheetModule.compile(PrincipalStylesheetModule.java:1244)
        at net.sf.saxon.style.Compilation.compilePackage(Compilation.java:322)
        at net.sf.saxon.style.StylesheetModule.loadStylesheet(StylesheetModule.java:252)
        at net.sf.saxon.style.Compilation.compileSingletonPackage(Compilation.java:113)
        at net.sf.saxon.s9api.XsltCompiler.compile(XsltCompiler.java:851)
        at net.sf.saxon.Transform.doTransform(Transform.java:753)
        at cli.Saxon.Cmd.DotNetTransform.Main(Unknown Source)
Fatal error during transformation: java.lang.UnsupportedOperationException:  (no message)

The above shows no errors in terms of failures to resolve/load the used WebClient and its constructor and its method but somehow fails otherwise.

I am not sure what to change.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Matt Klem 1 day ago

As an FYI, here is the other sheet I was given that uses Java instead of .NET (came from StackOverflow). This does work in Oxygen but spits up unusual errors in my tool.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:BufferedReader="java:java.io.BufferedReader"
    xmlns:InputStreamReader="java:java.io.InputStreamReader"
    xmlns:OutputStream="java:java.io.OutputStream"
    xmlns:HttpURLConnection="java:java.net.HttpURLConnection"
    xmlns:URL="java:java.net.URL"
    xmlns:JString="java:java.lang.String"
    xmlns:Stream="java:java.util.stream.Stream"
    xmlns:Charset="java:java.nio.charset.Charset"
    xmlns:ByteBuffer="java:java.nio.ByteBuffer"
    xmlns:StandardCharsets="java:java.nio.charset.StandardCharsets"
    xmlns:jt="http://saxon.sf.net/java-type"
    exclude-result-prefixes="#all"
    version="3.0">
    
    <xsl:param name="payload" as="xs:string" expand-text="no">{ "Name" : "John Doe", "Age" : 42 }</xsl:param>
    
    <xsl:param name="url" as="xs:string">https://httpbin.org/post</xsl:param>
   
    <xsl:template name="xsl:initial-template" expand-text="yes">
        <xsl:variable name="uri" as="xs:anyURI" select="xs:anyURI($url)"/>
        <xsl:variable name="java-url" as="jt:java.net.URL" select="URL:new($uri)"/>
        <xsl:variable name="conn" select="URL:openConnection($java-url)"/>
        <xsl:message select="HttpURLConnection:setRequestMethod($conn, 'POST')"/>
        <xsl:message select="HttpURLConnection:setRequestProperty($conn, 'Content-Type', 'application/json; utf-8')"/>
        <xsl:message select="HttpURLConnection:setRequestProperty($conn, 'Accept', 'application/json')"/>
        <xsl:message select="HttpURLConnection:setDoOutput($conn, true())"/> 
        <xsl:variable name="os" select="HttpURLConnection:getOutputStream($conn)"/>
        <xsl:variable name="utf8Charset" select="Charset:forName('utf-8')"/>
        <xsl:variable name="payloadJavaString" as="jt:java.lang.String" select="JString:new($payload)"/>
        <xsl:variable name="byteArray" select="ByteBuffer:array(Charset:encode($utf8Charset, $payloadJavaString))"/>
        <xsl:message select="OutputStream:write($os, $byteArray, 0, count($byteArray))"/>
        <xsl:message select="OutputStream:close($os)"/>
        <xsl:variable name="responseCode" select="HttpURLConnection:getResponseCode($conn)"/>
        <xsl:variable name="br" select="BufferedReader:new(InputStreamReader:new(HttpURLConnection:getInputStream($conn), 'utf-8'))"/>
        <xsl:variable name="response" select="BufferedReader:lines($br) => Stream:toArray()"/>
        <result code="{$responseCode}">{$response}</result>
    </xsl:template>
    
</xsl:stylesheet>

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 1 day ago

Matt,

can you try the code from https://saxonica.plan.io/boards/3/topics/9759?r=9764#message-9764 in your environment and tell us whether it works (not likely when it doesn't run through the Saxon EE .NET command line) and if it fails what error messages exactly it gives.

As for the example using Java that runs through Saxon from the command line and for you in oXygen but fails in your cloud environment, can you post the exact error message(s) you get there (if any) to see whether there is some way to adapt the code.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 1 day ago

As the stack of https://saxonica.plan.io/boards/3/topics/9759?r=9764#message-9764 suggests the let or xsl:variable might cause the crash (there doesn't seem to be a copy implementation of the DotNetExtensionFunctionCall) I have rewritten the code to not use that variable but do e.g.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  xmlns:WebClient="clitype:System.Net.WebClient?partialname=System.Net"
  exclude-result-prefixes="#all">

  <xsl:param name="staticWebClient" select="WebClient:new()"/>

  <xsl:param name="json-string" as="xs:string">{ "name" : "foo", "data" : [1, 2, 3] }</xsl:param>

  <xsl:param name="uri" as="xs:string" select="'https://httpbin.org/post'"/>

  <xsl:output method="text"/>

  <xsl:template match="/" name="main">
    <xsl:value-of select="WebClient:UploadString($staticWebClient, $uri, $json-string)"/>
    <xsl:text>&#10;Run with </xsl:text>
    <xsl:value-of select="system-property('xsl:product-name'), system-property('xsl:product-version'), 'at', current-dateTime()" separator=" "/>
  </xsl:template>

</xsl:stylesheet>

but unfortunately that gives a different crash

...
Finding best fit method with arguments:
java.lang.NullPointerException
        at net.sf.saxon.expr.Expression.getRetainedStaticContext(Expression.java:461)
        at net.sf.saxon.trace.ExpressionPresenter.startElement(ExpressionPresenter.java:302)
        at net.sf.saxon.expr.GlobalVariableReference.export(GlobalVariableReference.java:146)
        at com.saxonica.config.DotNetExtensionLibrary.getBestFit(DotNetExtensionLibrary.java:515)
        at com.saxonica.config.DotNetExtensionLibrary.bind(DotNetExtensionLibrary.java:418)
        at net.sf.saxon.functions.FunctionLibraryList.bind(FunctionLibraryList.java:126)
        at net.sf.saxon.expr.parser.XPathParser.parseFunctionCall(XPathParser.java:3279)
        at net.sf.saxon.expr.parser.XPathParser.parseBasicStep(XPathParser.java:2226)
        at net.sf.saxon.expr.parser.XPathParser.parseStepExpression(XPathParser.java:2102)
        at net.sf.saxon.expr.parser.XPathParser.parseRelativePath(XPathParser.java:2021)
        at net.sf.saxon.expr.parser.XPathParser.parsePathExpression(XPathParser.java:1983)
        at net.sf.saxon.expr.parser.XPathParser.parseSimpleMappingExpression(XPathParser.java:1997)
        at net.sf.saxon.expr.parser.XPathParser.parseUnaryExpression(XPathParser.java:1850)
        at net.sf.saxon.expr.parser.XPathParser.parseExprSingle(XPathParser.java:752)
        at net.sf.saxon.expr.parser.XPathParser.parseExpression(XPathParser.java:657)
        at net.sf.saxon.expr.parser.XPathParser.parse(XPathParser.java:519)
        at net.sf.saxon.expr.parser.ExpressionTool.make(ExpressionTool.java:91)
        at net.sf.saxon.style.StyleElement.makeExpression(StyleElement.java:699)
        at net.sf.saxon.style.XSLValueOf.prepareAttributes(XSLValueOf.java:55)
        at net.sf.saxon.style.StyleElement.processAttributes(StyleElement.java:594)
        at net.sf.saxon.style.StyleElement.processAllAttributes(StyleElement.java:531)
        at net.sf.saxon.style.StyleElement.processAllAttributes(StyleElement.java:534)
        at net.sf.saxon.style.XSLTemplate.processAllAttributes(XSLTemplate.java:428)
        at net.sf.saxon.style.PrincipalStylesheetModule.processAllAttributes(PrincipalStylesheetModule.java:589)
        at net.sf.saxon.style.PrincipalStylesheetModule.preprocess(PrincipalStylesheetModule.java:366)
        at net.sf.saxon.style.Compilation.compilePackage(Compilation.java:288)
        at net.sf.saxon.style.StylesheetModule.loadStylesheet(StylesheetModule.java:252)
        at net.sf.saxon.style.Compilation.compileSingletonPackage(Compilation.java:113)
        at net.sf.saxon.s9api.XsltCompiler.compile(XsltCompiler.java:851)
        at net.sf.saxon.Transform.doTransform(Transform.java:753)
        at cli.Saxon.Cmd.DotNetTransform.Main(Unknown Source)
Fatal error during transformation: java.lang.NullPointerException:  (no message)

That is HE/open-source code so it is online at https://saxonica.plan.io/projects/saxonmirrorhe/repository/he/revisions/he_mirror_saxon_10_9/entry/src/main/java/net/sf/saxon/expr/Expression.java#L461 but does a plain assert parent != null; that seems to cause the error.

No idea how to avoid that with the XSLT code.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 1 day ago

Even eliminating all variables and having the barebones XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:WebClient="clitype:System.Net.WebClient?partialname=System.Net"
  xmlns:NetString="clitype:System.String"
  exclude-result-prefixes="#all">

  <xsl:output method="text"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:value-of select="WebClient:UploadString(WebClient:new(), 'https://httpbin.org/post', '{ &quot;name&quot; : &quot;foo&quot;, &quot;data&quot; : [1, 2, 3] }')"/>
  </xsl:template>

</xsl:stylesheet>

without -TJ tells me

Error near {... "foo", "data" : [1, 2, 3] ...} at char 0 in xsl:value-of/@select on line 12 column 169 of http-post-webrequest-test4.xsl:
  XPST0017  Cannot find a 3-argument function named
  Q{clitype:System.Net.WebClient?partialname=System.Net}UploadString(). For diagnostics on
  calls to .NET methods, use the -TJ command line option or call
  processor.SetProperty("http://saxon.sf.net/feature/trace-external-functions", "true")
Errors were reported during stylesheet compilation

and the -TJ then tells me

Finding best fit method with arguments:
Trying option 0: System.String UploadString(System.String, System.String)
Arguments cannot be converted to required types
Trying option 1: System.String UploadString(System.Uri, System.String)
Arguments cannot be converted to required types
Number of candidates remaining: 0
There are 2 candidate .NET members matching the function name, but none is a unique best match
More than one method, property, or field matching WebClient:UploadString with 3 parameters found in class WebClient, and there is insufficient type information to decide which to use

I am not sure how to tell Saxon to use the XDM string passed in as a .NET System.String.

Perhaps Mike knows some way.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Matt Klem about 1 hour ago

As asked, here's a bunch of errors and screenshots showing my issue. postTest.xsl is the file that contains the Java/.Net code, and DocumentMaster.dmast is an XSLT sheet that calls the postTest.

When doing the Java version, this is what my tool shows:

Here is the actual error: Error Attribute end value delimiter expected. Line 37, position 73. XML Editor postTest.xsl Error EmptyTemplate.xaml DocumentMaster.dmast java.lang.NullPointerException


On the WebClient side, here's what I get:

Actual errors reported are:

Error Errors were reported during stylesheet compilation EmptyTemplate.xaml DocumentMaster.dmast Errors were reported during stylesheet compilation

Error 8:0 - Cannot find a 3-argument function named Q{clitype:System.Net.WebClient?partialname=System.Net}UploadString(). For diagnostics on calls to .NET methods, use the -TJ command line option or call processor.SetProperty("http://saxon.sf.net/feature/trace-external-functions", "true") Source: file:///C:/Users/MyUser/AppData/Local/Temp/Preview/Source/EmptyTemplate/EmptyTemplate_xaml/DocumentMaster_dmast/postTest.xsl EmptyTemplate.xaml postTest.xsl EDG.SaxonWrapper.SaxonWrapperException: 8:0 - Cannot find a 3-argument function named Q{clitype:System.Net.WebClient?partialname=System.Net}UploadString(). For diagnostics on calls to .NET methods, use the -TJ command line option or call processor.SetProperty("http://saxon.sf.net/feature/trace-external-functions", "true") Source: file:///C:/Users/MyUser/AppData/Local/Temp/Preview/Source/EmptyTemplate/EmptyTemplate_xaml/DocumentMaster_dmast/postTest.xsl

Error 6:0 - Conflicting values for output property method Source: file:///C:/Users/MyUser/AppData/Local/Temp/Preview/Source/EmptyTemplate/EmptyTemplate_xaml/DocumentMaster_dmast/postTest.xsl EmptyTemplate.xaml postTest.xsl EDG.SaxonWrapper.SaxonWrapperException: 6:0 - Conflicting values for output property method Source: file:///C:/Users/MyUser/AppData/Local/Temp/Preview/Source/EmptyTemplate/EmptyTemplate_xaml/DocumentMaster_dmast/postTest.xsl


In Oxygen, using the Java version, I get a valid data returned:

I can't test the .NET one in Oxygen because, honestly, I have no idea how to configure it to allow me to use the .NET extensions.

RE: Performing HTTP POST from XSLT using either Java or .NET calls from Saxon - Added by Martin Honnen 4 minutes ago

Just to make sure, can you show us your line 37 that is mentioned in the error message "Error Attribute end value delimiter expected. Line 37, position 73."?

    (1-11/11)

    Please register to reply