无法转换 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 " ">
]>
<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)
也是。
我有一个 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 " ">
]>
<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)
也是。