4

以下のXMLサンプルを考えます。

  1. 特定のオブジェクトが存在するかどうかを簡単に確認するにはどうすればよいですか?
  2. タイプグループまたはユーザーのアイテムを簡単に追加するにはどうすればよいですか?(ブロック全体を追加)

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

コード:

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;
4

2 に答える 2

4

1. XPath式を修正する方法は?

これらのいずれかでクエリが修正されます。

1)domを作成した後、次の行を追加します。

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

2)さらに良いことに、作成しているパーサーのバージョンをより明確にして、下書き線を次のように置き換えることができます。

Doc := CoDOMDocument60.Create; 

クエリで何も見つからない場合、ノードは空になります。

if not Assigned(Node) then...

MSXML3パーサーのデフォルトの照会言語はXSLPatternsです。明示的にXPathに設定する必要がありました。対処しなければならなかったのは久しぶりですが、CreateOleObject行でデフォルトのMSXMLパーサーを作成する必要があると思います。

更新:あなたの質問の後半の解決策は、優雅なTLamaから恥知らずに(許可を得て)盗まれました。:)

2.「制御」ノードを追加する方法は?

ターゲットドキュメントのフォーマットとエラー処理を無視します(例:次のように)。

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;
于 2012-08-28T21:58:03.263 に答える
2

この回答は、オーストラリアのDelphiユーザーグループのブログ「DanceswithXML」への私のエントリをまとめたものです。さらに詳細が必要な場合は、それを参照してください。

XMLを介したノードへのアクセス

XMLドキュメントにアクセスしてナビゲートするための簡単なメカニズムとしてXPATHを活用しようとすることで、正しい方向に向かっています。実装に少し磨きをかける必要があるというだけです。デモコードを以下に示します。

Q1特定のオブジェクトが存在するかどうかを簡単に確認するにはどうすればよいですか?

XPATH式で「in」演算子を使用し、参照される「DanceswithXML」ユーティリティユニットを使用します。たとえば、提供された入力ドキュメントを使用して、このコードフラグメントは制御ノードが存在するかどうかをテストします。

if 'role/access/control[type="group"]' in XFocus(Root) then
    ShowMessage(' Hello! I''m here.')

...ここで、Rootはドキュメントのルートノードです。

Q2タイプグループまたはユーザーのアイテムを簡単に追加するにはどうすればよいですか?

ものを追加するには、流暢なAPIを備えたXMLライブラリが最適ですが、次の方法で半流暢にすることができます。

子要素を追加する

子要素を追加するには、次のようなコードを使用します...

ParentNode.AddChild('child-name')

上記の式はIXMLNodeを返す関数であるため、これはやや流暢です。

属性を追加する

新しい属性を追加したり、既存の属性を変更したりするには、次のようなコードを使用します...

ElementNode.Attributes['myattrib'] := 'attrib-value'

この機能のネイティブべき等バージョンはありませんが、独自のバージョンを作成するのは簡単です。

例1

この例は、質問で与えられたOPのTest()プロシージャの機能を大まかに複製します。

// 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);

終わり;

例2

コンピューター管理者グループを追加したいとしますが、まだ存在していない場合に限ります。追加する場合、新しいノードは新しいアクセスノードの下に配置されます。XPATHを活用すれば、わずかな量のコードでこれを実現できます。これは、以下のコードフラグメントに示されています。

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;
于 2012-08-29T03:45:29.547 に答える