无法转换 XML "stylesheet does not contain a document element"(无处不在,但 delphi)

Cannot transform XML "stylesheet does not contain a document element" (works everywhere but delphi)

我有一个 XSL 文件,在我尝试过的每个地方都可以正常工作,但 Delphi 除外。适用于 Web 解析器(例如 https://xslttest.appspot.com/)以及使用 Microsoft 的 msxsl.exe 时。

但是,下面的代码在 Delphi 10.2 中调用 transformNode() 时出现异常:

The stylesheet does not contain a document element. The stylesheet may be empty, or it may not be a well-formed XML document.

据我了解,这应该使用与 msxsl 相同的 MSXML?

uses
  Winapi.MSXML;

procedure TForm1.Button1Click(Sender: TObject);
var
  transformstring: string;
  xmldoc, xsldoc: IXMLDOMDocument3;
begin

  xmldoc := CoDOMDocument60.Create;
  xsldoc := CoDOMDocument60.Create;

  xmldoc.load('C:\Temp\Data.xml');
  xsldoc.load('C:\Temp\Stylesheet.xsl');
  xsldoc.setProperty('AllowXsltScript', True);

  transformstring := xmldoc.transformNode(xsldoc);
end;

XSL 文件是(已最小化):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp "&#160;">
]>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:param name="D2DSeverityFilter">^Caution^Minor^Moderate^Severe^</xsl:param>
  <xsl:param name="D2HSeverityFilter">^Extreme Caution^Contraindication^Contraindicated^</xsl:param>
  <xsl:param name="DocumentationFilter">^Not Established^Limited^Good^Well Established^</xsl:param>
  <xsl:output method="html" omit-xml-declaration="yes"/>


</xsl:stylesheet>

输入数据似乎不相关,但为了完整起见,这个空文件可以使用:

<?xml version="1.0" encoding="windows-1252"?>
<Result ></Result>

固定代码如下,包括需要设置的额外属性。

uses
  Winapi.MSXML;

procedure TForm1.Button1Click(Sender: TObject);
var
  transformstring: string;
  xmldoc, xsldoc: IXMLDOMDocument3;
begin

  xmldoc := CoDOMDocument60.Create;
  xsldoc := CoDOMDocument60.Create;

  xmldoc.load('C:\Temp\Data.xml');

  xsldoc.setProperty('AllowXsltScript', True);
  xsldoc.setProperty('ProhibitDTD', False);
  xsldoc.setProperty('ValidateOnParse', False);
  xsldoc.load('C:\Temp\Stylesheet.xsl');

  transformstring := xmldoc.transformNode(xsldoc);
end;

有不同版本的 MSXML,您的 Delphi 代码似乎尝试使用 MSXML 6。出于安全原因,我认为它对各种属性具有不同的默认设置,其中之一与 DTD 相关.因此,鉴于您的 XSLT 示例尝试使用 DTD,我认为您需要明确允许它,请参阅 https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms762632%28v%3dvs.85%29.

因此我认为在 load 调用 xsldoc.setProperty('ProhibitDTD', False) 之前设置 load 应该会有帮助。

此外,正如我们在评论部分整理出的那样,使用 DTD 和 MSXML 6 默认设置来尝试验证由 load 调用解析的文档会阻止您的样式表被处理,因为该 DTD 片段显然没有指定 XSLT 样式表的完整语法。因此,您需要设置

xsldoc.setProperty('ValidateOnParse', False)

也是。