Search code examples
xmldelphidelphi-2010ixmldomdocument

Search data in XML using IXMLDocument


Given the XML sample below;

  1. How can I easily check if a given object exists?
  2. How can I easily add an item of type group or user? (add a whole block)

<role>
    <access>
        <control>
            <type>group</type>
            <object>COMPUTER\Administrators</object>
        </control>
        <control>
            <type>user</type>
            <object>COMPUTER\Admin</object>
        </control>
    </access>
</role>

Code:

var
  Doc: IXMLDOMDocument2;
  Node: IXMLDOMNode;
procedure Test;
begin
  Doc := CreateOleObject('Microsoft.XMLDOM') as IXMLDomDocument2;
  Doc.load('test.xml');

  // This Works
  Node := Doc.selectSingleNode('//role/access/control');

  // But this does not work:
  Node := Doc.selectSingleNode('//role/access/control[type = ''group'']');

  // EDIT: This does work, but how to combine with object=COMPUTER\Admin?
  Node := Doc.selectSingleNode('//role/access/control[type="group"]');

  // EDIT: This does not work either
  Node := Doc.selectSingleNode('//role/access/control[type="group" and object="COMPUTER\Administrators"]');
end;

Solution

  • 1. How to fix the XPath expression ?

    Either of these will fix the query:

    1) Add the following line after creating the dom:

      Doc.setProperty('SelectionLanguage', 'XPath');
    

    2) Better yet, you could be more explicit about which version of the parser you are creating and replace your construction line with this:

    Doc := CoDOMDocument60.Create; 
    

    If the query doesn't find anything, Node will be empty.

    if not Assigned(Node) then...
    

    The default query language for the MSXML3 parser is XSLPatterns. You needed to explicitly set it to XPath. It's been a while since I've had to deal with it, but I assume the CreateOleObject line must create the MSXML parser my default.

    Update: Solution for the second half of your question stolen shamelessly (with permission) from the gracious TLama. :)

    2. How to add a "control" node ?

    Ignoring target document formatting and error handling e.g. this way:

    procedure TForm1.Button2Click(Sender: TObject);
    var
      XMLRoot: IXMLDOMNode;
      XMLChild: IXMLDOMNode;
      XMLDocument: IXMLDOMDocument2;
    begin
      XMLDocument := CreateOleObject('Microsoft.XMLDOM') as IXMLDomDocument2;
      XMLDocument.load('XMLFile.xml');
      XMLRoot := XMLDocument.selectSingleNode('//role/access');
      if Assigned(XMLRoot) then
      begin
        XMLRoot := XMLRoot.appendChild(XMLDocument.createElement('control'));
        XMLChild := XMLRoot.appendChild(XMLDocument.createElement('type'));
        XMLChild.text := 'user';
        XMLChild := XMLRoot.appendChild(XMLDocument.createElement('object'));
        XMLChild.text := 'COMPUTER\TLama';
        XMLDocument.save('XMLFile.xml');
      end;
    end;