Можно ли преобразовать msxml.IXMLDOMNode в XmlIntf.IXMLNode в Delphi?

Я прочитал som xml в объект msxml.IXMLDOMDocument. Однако в API, который я использую, есть метод утилиты, который я бы хотел вызвать, но в качестве аргумента он принимает XmlIntf.IXMLNode.

Есть ли простой способ конвертировать экземпляр IXMLDOMNode из моего документа в IXMLNode, чтобы я мог передать его методу без необходимости загружать xml в объект TXmlDocument?

На данный момент я применил это обходное решение:

function ConvertNode(const Node: IXMLDOMNode): IXMLNode;
var
  Document: IXMLDocument;
begin
  Document := NewXMLDocument;
  Document.LoadFromXML(Node.xml);
  Result := Document.DocumentElement;
end;

Ответ 1

Вы можете создать экземпляр IXMLDocument и "прикрепить" его к вашему IXMLDOMDocument. Вот небольшой пример:

program msxmltest;

{$APPTYPE CONSOLE}

uses
  SysUtils, ActiveX,
  msxml, msxmldom,
  xmldom,
  XMLIntf, XMLDoc;

function MSDOMDocumentToDOMDocument(const MSDOMDocument: IXMLDOMDocument): IDOMDocument;
begin
  Result := TMSDOMDocument.Create(MSDOMDocument) as IDOMDocument;
end;

function MSDOMNodeToDOMNode(const MSDOMNode: IXMLDOMNode): IDOMNode;
const
  NodeClasses: array[ELEMENT_NODE..NOTATION_NODE] of TMSDOMNodeClass =
    (TMSDOMElement, TMSDOMAttr, TMSDOMText, TMSDOMCDataSection,
     TMSDOMEntityReference, TMSDOMEntity, TMSDOMProcessingInstruction,
     TMSDOMComment, TMSDOMDocument, TMSDOMDocumentType, TMSDOMDocumentFragment,
     TMSDOMNotation);
begin
  Result := NodeClasses[MSDOMNode.nodeType].Create(MSDOMNode) as IDOMNode;
end;

function MSDOMNodeToXMLNode(const MSDOMNode: IXMLDOMNode; var OwnerDocument: IXMLDocument): IXMLNode;
begin
  Result := nil;
  if not Assigned(MSDOMNode) then
    Exit;
  if not Assigned(OwnerDocument) then
  begin
    OwnerDocument := TXMLDocument.Create(nil);
    OwnerDocument.DOMDocument := MSDOMDocumentToDOMDocument(MSDOMNode.ownerDocument);
  end;
  Result := TXMLNode.Create(MSDOMNodeToDOMNode(MSDOMNode), nil, (OwnerDocument as IXMLDocumentAccess).DocumentObject);
end;

var
  Indent: Integer = 0;

procedure ShowNode(const Node: IXMLNode);
var
  I: Integer;
begin
  Inc(Indent);
  Writeln;
  Writeln(StringOfChar(' ', Indent * 2) + 'NodeName: ' + Node.NodeName);
  Writeln(StringOfChar(' ', Indent * 2) + 'NodeType: ' + NodeTypeNames[Node.NodeType]);
  for I := 0 to Node.AttributeNodes.Count - 1 do
    ShowNode(Node.AttributeNodes[I]);
  if Node.HasChildNodes then
    for I := 0 to Node.ChildNodes.Count - 1 do
      ShowNode(Node.ChildNodes[I])
  else
    Writeln(StringOfChar(' ', Indent * 2) + 'NodeValue: ' + Node.NodeValue);
  Dec(Indent);
end;

procedure Main;
var
  MSDOMDocument: IXMLDOMDocument;
  XMLDocument: IXMLDocument;
  MSDOMNode: IXMLDOMNode;
begin
  MSDOMDocument := CoDOMDocument.Create;
  MSDOMDocument.load('C:\Program Files\Embarcadero\RAD Studio\8.0\ObjRepos\en\Code_Templates\Delphi\blockcomment.xml');
  MSDOMNode := MSDOMDocument.documentElement;
  // show all
  ShowNode(MSDOMNodeToXMLNode(MSDOMNode, XMLDocument)); // you can reuse XMLDocument
  Writeln;
  // show author
  MSDOMNode := MSDOMDocument.selectSingleNode('/codetemplate/template/author');
  ShowNode(MSDOMNodeToXMLNode(MSDOMNode, XMLDocument));

  Readln;
end;


begin
  ReportMemoryLeaksOnShutdown := True;
  try
    CoInitialize(nil);
    try
      Main;
    finally
      CoUninitialize;
    end;
  except
    on E: Exception do
    begin
      ExitCode := 1;
      Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
    end;
  end;
end.