Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I convert a msxml.IXMLDOMNode to XmlIntf.IXMLNode in Delphi?

I have read som xml into an msxml.IXMLDOMDocument object. However, there is a utility method in an API that I am using, that I would like to call, but it takes an XmlIntf.IXMLNode as an argument.

Is there a simple way to convert an IXMLDOMNode instance from my document to an IXMLNode so I can pass it to the method without having to load the xml into a TXmlDocument object?

For now I have implemented this workaround:

function ConvertNode(const Node: IXMLDOMNode): IXMLNode;
var
  Document: IXMLDocument;
begin
  Document := NewXMLDocument;
  Document.LoadFromXML(Node.xml);
  Result := Document.DocumentElement;
end;
like image 812
Mathias Falkenberg Avatar asked Nov 16 '11 08:11

Mathias Falkenberg


1 Answers

You can create an instance of IXMLDocument and "attach" it to your IXMLDOMDocument. Here's a small example:

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.
like image 64
Ondrej Kelle Avatar answered Nov 11 '22 11:11

Ondrej Kelle