从 JavaScript 调用 Saxon-JS 函数或模板

Calling Saxon-JS function or template from JavaScript

我使用 C3 在使用 Saxon-JS 和(已编译,SEF)XSL 样式表的 HTML 页面中呈现图表。 C3生成SVG图片(条形图),并提供了响应点击事件的可能性(比如条形图),带有onclick函数。

c3.generate(
  { bindto: ...
  , data:
    { type: 'bar'
    , columns: c3_columns
    , onclick: function(data, element) { ... }
    }
    ...
  })

我想在我的 XSL 样式表中处理点击事件。 然而:

这个场景有点复杂,但我将包括两个简化的代码示例,希望能展示我正在尝试做的事情。

在 Javascript 我有 onclick 处理程序。

function chartClickHandler(data, element) {
  // Show the contents of the data.
  console.log(`Click on chart`);
  Object.entries(data).forEach(([k, v]) => console.log(`  ${k} : ${v}`));
  // Send a custom event.
  const event = new CustomEvent('chartclick', data);
  document.getElementsByTagName('body')[0].dispatchEvent(event);
  // Call a function in the XSL stylesheet.
  SaxonJS.XPath.evaluate(`chart:click('hello chartCLick')`, [],
    { namespaceContext: {'chart' : 'chart'}
    });
}

这是从 HTML 调用的。为简单起见,我不使用 C3,但是:

<button onclick="chartClickHandler({x: 1, y: 2}, this)">test</button>

在提供给 Saxon-JS 的 XSL 样式表中,我有:

  <xsl:template match="body" mode="ixsl:onchartclick">
    <xsl:if test="$show-debug-messages">
      <xsl:message>
        Chartclick event properties: <xsl:value-of select="ixsl:eval('Object.keys') => ixsl:apply([ixsl:event()])"/>
      </xsl:message>
    </xsl:if>
  </xsl:template>

  <xsl:function xmlns:chart="chart" name="chart:click">
    <xsl:param name="data"/>
    <xsl:message>
      Chart click data: <xsl:value-of select="serialize($data)"/>
    </xsl:message>
  </xsl:function>

如前所述,我得到的只是

Click on chart debugger eval code:3:11
  x : 1 debugger eval code:4:52
  y : 2 debugger eval code:4:52
Uncaught 
Object { message: "Unknown function Q{chart}click()", stack: ...

这个例子还是涉及到很多部分,但是我的问题的本质在标题中: 如何从 JavaScript 调用 Saxon-JS 函数或模板。或者如何拦截自定义事件。

正如我在评论中所说,我认为要在 SEF 中调用函数,您应该使用 SaxonJS.transform({ initialFunction : 'Q{namespace-uri}function-name', functionParams: [function arguments here], ..}, ..)

例如https://martin-honnen.github.io/xslt/2022/xsltFunctionCallTest2.html

内容:

<html lang="en">
  <head>
    <title>Saxon-JS 2 test</title>
    <script src="../../Saxon-JS-2.3/SaxonJS2.rt.js"></script>
    <script>
    var internalStylesheet;
    document.addEventListener('DOMContentLoaded', e => {
      var options = { 
        stylesheetLocation : 'xsltFunctionCallTest1.xsl.sef.json',
        sourceLocation: 'sample1.xml',
        destination: 'appendToBody'
      };
      SaxonJS.transform(options, 'async').then(result => { internalStylesheet = result.stylesheetInternal; console.log(internalStylesheet); console.log(result); });
    });
    </script>
    <script>
      function functionCallTest1() {
       SaxonJS.transform({ destination: 'raw', stylesheetLocation : 'xsltFunctionCallTest1.xsl.sef.json', initialFunction: 'Q{http://example.com/mf}f1', functionParams: [ { x: 1, y: 'foo' }] }, 'async').then(result => console.log(result.principalResult)); 
      }
    </script>
  </head>
  <body>
    <h1>Test</h1>
  </body>
</html>

第一个转换生成的地方,例如

<section>
  <h2>Test</h2>
  <p>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</p>
  <input type="button" value="test"
    onclick="functionCallTest1();"/>
</section>

警告:在 XSLT 中,确保您在 XSLT xsl:function 上声明了 visibility="public"