SaxonJS.XPath.evaluate( fn:transform() ) 的结果不返回根文档节点

问题描述 投票:0回答:1

对于 NodeJs 工具,我必须使用 XSLT 执行简单的 XML 转换。

我想使用 SaxonJs,但我不想参与整个 xslt3/sef 的事情(xslt 发生变化,该工具需要在没有安装 xslt3 的计算机上运行)。

还有一种替代方法,那就是在 XPath 表达式中使用

fn:transform
函数。

虽然它似乎完全按照我想要的方式工作,但当我使用某些表达式时,我无法对结果执行任何 XPath ,因为根据 SaxonJs,根节点不是文档节点。

所以这有效:

/*[1]/*[1]

但这不是:

//*[@someAttr]/name

因为然后我收到此错误:

Exception has occurred: XError: Root node for '/' must be a document node

当我在源文档上使用第二个 XPath 表达式时,没有收到错误。

此外,当我序列化源和结果并比较它们时,它们在各个方面都是相同的(!)(除了属性值的微小变化,但这就是 XSLT 应该做的)

这是我的代码:

const applyXsltToXml = function (xmlData, transformXslt) {

  const filteredXML = SaxonJS.XPath.evaluate(
    `fn:transform(map { ` +
      `'source-node': fn:parse-xml($xml), ` +
      `'stylesheet-node': fn:parse-xml($xslt), ` +
      `'delivery-format': 'raw' ` +
    `})?output`,
    null,
    { 'params': { 'xml': xmlData, 'xslt': transformXslt } }
  );

  if (_debug) {
    _write(`Xml transformed using Xslt; root node "${filteredXML?.localName}"`);
  }

  return filteredXML;
}

在我看来,问题在于 XDM 的结果在某种程度上不正确。当我比较源文档的 XDM 和结果 XML 的结果时我看到的差异:

  • sourceDoc
    具有
    documentElement
    属性
  • 这个
    sourceDoc.documentElement
    也有
    $d
    属性,但在
    transformedDoc
    的 XDM 中,它是直接子级(
    $d
    包含命名空间)
  • localName
    /
    nodeName
    /
    tagName
    也是
    transformedDoc
    的直接属性,而在
    sourceDoc
    中可以在属性
    firstChild
  • 中看到它们

这是我正在使用的 XSLT:

let xslt = `<?xml version="1.0"?>
  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
      <xsl:template match="@*|node()">
          <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
      </xsl:template>
  
      <!-- Filter out @cmyk -->
      <xsl:template match="@cmyk"/>
  
  </xsl:stylesheet>
  `;

似乎只有一件小事出了问题,但我看不出来。我一直在查看

fn:transform
的论点,但找不到任何东西。难道和
?output
有关系吗?

或者我需要以某种方式将结果转换成文档吗?


更新

感谢@martin-honnen,我现在知道问题出在

.xslt
样式表上。

我尝试了稍微不同的 xslt v1 副本,但这也不起作用。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output omit-xml-declaration="yes" indent="no"/>
  
        <xsl:template match="node() | @*">
          <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
          </xsl:copy>
        </xsl:template>
  
      <!-- Filter out -->
      <xsl:template match="@cmyk"/>
  
  </xsl:stylesheet>

什么可以解释这一点?

xml xpath xslt saxon-js
1个回答
0
投票

我将为您提供一个使用 SaxonJS 2(在 Node.js 下使用 2.6 进行测试)针对 XML 示例运行与您类似的样式表(适合使用 XSLT 3 功能)的示例,以将转换结果作为 XDM 文档返回,其中随后执行 XPath 评估:

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

const applyXsltToXml = function (xmlData, transformXslt) {

  const filteredXML = SaxonJS.XPath.evaluate(
    `transform(map {
      'source-node': fn:parse-xml($xml),
      'stylesheet-node': fn:parse-xml($xslt),
      'delivery-format': 'raw'
    })?output`,
    null,
    { 'params': { 'xml': xmlData, 'xslt': transformXslt } , resultForm : 'xdm'}
  )[0];

  return filteredXML;
}


const xmlExample1 = `<root>
  <foo>bar</foo>
  <bar cmyk="...">test</bar>
</root>`;

const xsltExample1 = `<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
      <xsl:mode on-no-match="shallow-copy"/>
  
      <!-- Filter out @cmyk -->
      <xsl:template match="@cmyk"/>
  
  </xsl:stylesheet>`;
  
const resultExample1 = applyXsltToXml(xmlExample1, xsltExample1);

console.log(resultExample1);

const result2 = SaxonJS.XPath.evaluate(`count(//@cmyk)`, resultExample1);

console.log(result2);

最终的 XPath 评估返回 0。

© www.soinside.com 2019 - 2024. All rights reserved.