delphi 无法通过TXMLDocument枚举XML树

6xfqseft  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(142)

我尝试在 Delphi 中使用TXMLDocument来枚举XML文件。但是每当我退出ProcessFile过程时,都会出现“Access violation”异常。
我将XMLFile声明为接口对象IXMLDocument,而不是TXMLDocument,并且不手动调用free。
下面是代码:

//  Invoke ProcessFile in the main app
ProcessFile('C:\Myfile.xlf', True);

//  Process the node recursively
procedure ProcessNode1(Node: IXMLNode);
var
  Index: Integer;
begin
  if (Node.NodeName = 'trans-unit') then
  begin
    //  Process 'trans-unit'
  end
  else
    for Index := 0 to Node.ChildNodes.Count - 1 do
      ProcessNode1(Node.ChildNodes[Index]);
end;

procedure ProcessFile(const SrcFileName: string; const FixMode: Boolean);
var
  XmlFile: IXMLDocument;
  MainNode, FileNode: IXMLNode;
  OriginalFileName, SrcLang, DstLang: string;
begin
  //  Initialize the COM, otherwise we cannot use MSXML
  CoInitialize(nil);

  //  Open the XML document
  XmlFile := TXMLDocument.Create(nil);
  try
    XmlFile.LoadFromFile(SrcFileName);
    //  XmlFile.Active := True;

    MainNode := XmlFile.DocumentElement;
    FileNode := MainNode.ChildNodes['file'];

    OriginalFileName := FileNode.GetAttribute('original');
    SrcLang := FileNode.GetAttribute('source-language');
    DstLang := FileNode.GetAttribute('target-language');

    //  Output the information
    //  If removing the following statement, then everything will be OK.
    Writeln(Format('Call TranslateFile. OriginFile: %s. SrcFile: %s. SrcLang: %s. DstLang: %s. FixMode: %s.',
          [OriginalFileName, ExtractFileName(SrcFileName), SrcLang, DstLang, BoolToStr(FixMode, True)]));

    //  Enumerate the DOM tree
    ProcessNode1(FileNode);
  finally
    CoUninitialize;
  end;
end;

Blow是XML文档

<?xml version="1.0" encoding="utf-16"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd" xmlns:soluling="http://www.soluling.com">
  <file original="a.rc" source-language="en-US" target-language="bg-BG" datatype="plaintext">
    <body>
      <group id="String" datatype="winres">
        <group id="IDS_TEST">
          <trans-unit id="String.IDS_TEST1">
            <source>a</source>
            <target state="translated" state-qualifier="fuzzy-match">b</target>
            <soluling:datatype>string</soluling:datatype>
            <soluling:rowstatus>rsInUse</soluling:rowstatus>
          </trans-unit>
        </group>
      </group>
    </body>
  </file>
</xliff>
xzlaal3s

xzlaal3s1#

XmlFileMainNodeFileNode对象仍然处于活动状态时,您正在调用CoUninitialize(),因此当它们在ProcessFile()退出时超出作用域时,RTL无法正确释放它们,因此出现了访问冲突。
在卸载COM库之前,您需要清除这些引用,例如:

procedure ProcessFile(const SrcFileName: string; const FixMode: Boolean);
var
  XmlFile: IXMLDocument;
  MainNode, FileNode: IXMLNode;
  ...
begin
  //  Initialize the COM, otherwise we cannot use MSXML
  CoInitialize(nil);
  try
    //  Open the XML document
    XmlFile := LoadXMLDocument(SrcFileName);
    try
      MainNode := XmlFile.DocumentElement;
      FileNode := MainNode.ChildNodes['file'];
      ...
    finally
      // ADD THIS!
      FileNode := nil;
      MainNode := nil;
      XmlFile := nil;
    end;
  finally
    CoUninitialize;
  end;
end;

或者,将COM库的加载/卸载与树处理代码分开,例如:

procedure DoProcessFile(const SrcFileName: string; const FixMode: Boolean);
var
  XmlFile: IXMLDocument;
  MainNode, FileNode: IXMLNode;
  ...
begin
  //  Open the XML document
  XmlFile := LoadXMLDocument(SrcFileName);
  MainNode := XmlFile.DocumentElement;
  FileNode := MainNode.ChildNodes['file'];
  ...
end;

procedure ProcessFile(const SrcFileName: string; const FixMode: Boolean);
begin
  //  Initialize the COM, otherwise we cannot use MSXML
  CoInitialize(nil);
  try
    DoProcessFile(SrcFileName, FixMode);
  finally
    CoUninitialize;
  end;
end;

相关问题