Shukai Ni
Shukai Ni

Reputation: 467

Error when running SaxonJS in Node JS, "Context item for '/' must be a node"

const node = document.createElement('div');
node.innerHTML = "<p>Text 1</p>"

For this JS HTMLElement, how should I run an XPath against it using SaxonJS?

const res = saxonJs.XPath.evaluate('//p', node);

Has error Context item for '/' must be a node

const res = saxonJs.XPath.evaluate('*', node);

Has error Context item for child axis is not a node - supplied:HashTrie map{}

MORE DETAILS: The ultimate goal is to run XPath 3.0 against an HTML DOM (parsed from a string) in Node JS, so I'm open to using other modules or methods

Upvotes: 1

Views: 248

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167436

Inside the browser there is always one sole DOM implementation that both SaxonJS and the browser use so there you can indeed use HTML DOM document and nodes as context items, even if not officially supported in e.g. https://www.saxonica.com/saxon-js/documentation2/index.html#!api/getResource (by adding html as a possible type).

const html = `<p>This is a test.
<p>This is a test.
<ul>
  <li>a</li>
  <li>1</li>
  <li>b</li>
</ul>`;

const htmlDoc = new DOMParser().parseFromString(html, 'text/html');

const alphabeticLIElements = SaxonJS.XPath.evaluate("//li[matches(., '\\p{L}+')]", htmlDoc, { xpathDefaultNamespace : 'http://www.w3.org/1999/xhtml' });

console.log(alphabeticLIElements);
<script src="https://www.saxonica.com/saxon-js/documentation2/SaxonJS/SaxonJS2.rt.js"></script>

Inside Node.js, things, as far as I understand, are different, the SaxonJS internalizes some third party DOM implementation (which by now might be compatible to support text/html parsing) but doesn't expose any method or way for HTML parsing.

I did a feature request https://saxonica.plan.io/issues/5302 (or two) on that some while ago but so far there has been no new release on the 2.x branch to implement or expose that.

So I afraid, unless you find a way through the Node.js module structure to access the internalized DOM implementation, there is currently no way to achieve that.

The official way, once implemented/exposed, I think would be along the lines of

const SaxonJS = require("saxon-js");

const html = `<p>This is a test.
<p>This is a test.
<ul>
  <li>a</li>
  <li>1</li>
  <li>b</li>
</ul>`;

SaxonJS.getResource({ type : 'html', text: html }).then(htmlDoc => {

console.log(htmlDoc);

const alphabeticLIElements = SaxonJS.XPath.evaluate("//li[matches(., '\\p{L}+')]", htmlDoc, { xpathDefaultNamespace : 'http://www.w3.org/1999/xhtml' });

console.log(alphabeticLIElements);
}).catch(err => console.log(err));

Upvotes: 2

Related Questions