Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This answer summarizes my entry on the Australian Delphi User's Group blog, <a href="http://members.adug.org.au/2012/08/17" rel="nofollow">"Dances with XML"</a>. Refer to it if you need further detail.</p> <h2>Access to nodes via XML</h2> <p>You are headed in the right direction, by trying to leverage XPATH as an easy mechanism to access and navigate through an XML document. It just that your implementation needs a bit of polishing. Demonstrative code is shown below.</p> <h2>Q1 How can I easily check if a given object exists?</h2> <p>Use the 'in' operator with an XPATH expression, and the referenced "Dances with XML" utility unit. For example with your supplied input document, this code fragment tests if a control node exists with a</p> <pre><code>if 'role/access/control[type="group"]' in XFocus(Root) then ShowMessage(' Hello! I''m here.') </code></pre> <p>...where Root is the document root node.</p> <h2>Q2 How can I easily add an item of type group or user?</h2> <p>For adding stuff, an XML library with a fluent API would be best, but you can achieve semi-fluency with the following methods:</p> <h3>Add a child element</h3> <p>To add a child element use code like this...</p> <pre><code>ParentNode.AddChild('child-name') </code></pre> <p>This is semi-fluent because this above expression is a function which returns IXMLNode.</p> <h3>Add an attribute</h3> <p>To add a new attribute, or change an existing one use code like this...</p> <pre><code>ElementNode.Attributes['myattrib'] := 'attrib-value' </code></pre> <p>There is no native idempotent version of this functionality, but it would be trivial to roll your own.</p> <h2>Example 1</h2> <p>This example roughly replicates the functionality of the OP's Test() procedure given in the question.</p> <pre><code>// uses uXMLUtils from referenced demo. procedure Test; begin Doc := LoadDocument_MSXML_FromStream( TestXMLStream); Root := Doc.Node; // To test if control node exists: if 'role/access/control' in XFocus(Root) then ShowMessage('The control node exists!'); // To access each control node: for ControlNode in 'role/access/control' then DoSomethingForEachControlNode( ControlNode); // To access on the first control node: for ControlNode in '(role/access/control)[1]' then DoSomethingForFirstControlNode( ControlNode); // To access on the first control node which has BOTH group type and Admin object: for ControlNode in '(role/access/control[type="group"][object="COMPUTER\Administrators"])[1]' do DoSomething( ControlNode); // To do something for EACH control node which is EITHER group type or Admin object: for ControlNode in 'role/access/control[type="group" or object="COMPUTER\Administrators"]' do DoSomething( ControlNode); </code></pre> <p>end;</p> <h2>Example 2</h2> <p>Let's say we want to add a computer administrators group, but only if one does not already exist. If adding, the new nodes go under a new access node. We can achieve this with a trivial amount of code if we leverage XPATH. This is shown in the code fragment below.</p> <pre><code>if not 'role/access/control[type[.="group"][object[.="COMPUTER\Administrators"]]' in XFocus(Root) then begin ControlNode := Root.ChildNodes.FindNode('role') .AddChild(['access') .AddChild('control'); ControlNode.AddChild('type' ).Text := 'group'; ControlNode.AddChild('object').Text := 'COMPUTER\Administrators' end; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload