You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 11.3中FormatXMLData格式化SVG报无效节点类型异常的解决方法

修复Delphi 11.3中FormatXMLData处理SVG XML时的"Invalid node type"异常

问题背景

我有一个由Affinity Designer导出的SVG文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 67 67" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><g id="icon"><path d="M64.583,8.333c0,-3.449 -2.8,-6.25 -6.25,-6.25l-50,0c-3.449,0 -6.25,2.801 -6.25,6.25l0,50c0,3.45 2.801,6.25 6.25,6.25l50,0c3.45,0 6.25,-2.8 6.25,-6.25l0,-50Z" style="fill:#ebebeb;fill-opacity:0;stroke:#0dcaf2;stroke-width:4.01px;"/><g><circle cx="46.657" cy="16.816" r="8.809" style="fill:#f3ca69;"/><path d="M59.761,54.246l-15.758,-21.165c-0.508,-0.683 -1.548,-0.681 -2.054,0.003l-7.002,9.485l-11.004,-14.732c-0.506,-0.679 -1.525,-0.679 -2.032,-0l-14.753,19.758c-0.163,0.219 -0.253,0.485 -0.253,0.758l0,10.307l52.856,0l0,-4.414Z" style="fill:#4ea17e;fill-rule:nonzero;"/></g></g></svg>

在Delphi 11.3中,使用以下代码加载该文件并尝试用FormatXMLData格式化时触发Invalid node type异常(异常类型为EXMLDocError):

var ThisXMLDoc := Xml.XMLDoc.TXmlDocument.Create(nil);
try
  ThisXMLDoc.LoadFromFile(EditSVGPath.Text);
  var FormattedSVGText := Xml.XMLDoc.FormatXMLData(ThisXMLDoc.XML.Text); // 触发异常
finally
  ThisXMLDoc.Free;
end;

错误细节更新:异常发生在Xml.XMLDoc.pas中的CloneNodeToDoc函数,该函数仅允许处理节点类型为ntElement、ntAttribute、ntText、ntCData、ntComment、ntEntityRef、ntProcessingInstr或ntDocFragment的节点,而FormatXMLData传入的节点类型不在此范围内。

修复方案

原因分析

SVG文件中的DOCTYPE声明被解析为ntDocumentType类型节点,而Delphi原生的FormatXMLData函数不支持处理该类型节点,导致校验失败抛出异常。

具体解决方法

方法1:加载XML时忽略DTD声明

通过添加doNotLoadDTD选项,让XML解析器跳过DOCTYPE节点的加载,避免触发不支持的节点类型校验:

var ThisXMLDoc := Xml.XMLDoc.TXmlDocument.Create(nil);
try
  ThisXMLDoc.Options := ThisXMLDoc.Options + [doNotLoadDTD];
  ThisXMLDoc.LoadFromFile(EditSVGPath.Text);
  var FormattedSVGText := Xml.XMLDoc.FormatXMLData(ThisXMLDoc.XML.Text);
finally
  ThisXMLDoc.Free;
end;

方法2:预处理文本移除DOCTYPE后再格式化

如果需要保留XML声明但可舍弃DOCTYPE,可先读取文件文本,移除DOCTYPE部分后再格式化:

var
  RawSVGText: string;
  FormattedSVGText: string;
begin
  // 读取原始SVG文件内容
  RawSVGText := TFile.ReadAllText(EditSVGPath.Text);
  // 移除DOCTYPE声明
  RawSVGText := TRegEx.Replace(RawSVGText, '<!DOCTYPE[^>]+>', '', [roIgnoreCase]);
  // 执行格式化
  FormattedSVGText := Xml.XMLDoc.FormatXMLData(RawSVGText);
end;

若业务需要保留DOCTYPE,可在格式化后手动将其添加回XML头部。

方法3:仅格式化根节点XML内容

直接获取SVG根节点的XML内容进行格式化,避开文档级的DOCTYPE节点,之后可手动补回XML声明:

var
  ThisXMLDoc: Xml.XMLDoc.TXmlDocument;
  RootNode: IXMLNode;
  FormattedSVGText: string;
begin
  ThisXMLDoc := Xml.XMLDoc.TXmlDocument.Create(nil);
  try
    ThisXMLDoc.LoadFromFile(EditSVGPath.Text);
    RootNode := ThisXMLDoc.DocumentElement;
    // 格式化根节点的XML
    FormattedSVGText := Xml.XMLDoc.FormatXMLData(RootNode.XML);
    // 手动添加XML声明(按需)
    FormattedSVGText := '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' + sLineBreak + FormattedSVGText;
  finally
    ThisXMLDoc.Free;
  end;

内容的提问来源于stack exchange,提问作者user1580348

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:02:01