【问题标题】:Search data in XML using IXMLDocument使用 IXMLDocument 在 XML 中搜索数据
【发布时间】:2012-08-28 19:40:44
【问题描述】:

鉴于下面的 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;

【问题讨论】:

  • @Adam:+1 好点,这是我的错误,所以我用正确的截图替换了截图。
  • 你们为什么要发布文本文件的截图?只是好奇...
  • @Adam,因为他们不应该这样。 :-) XML 应该作为文本内容发布(并且正确格式化也不难),以便想要在发布之前检查答案的人可以复制和粘贴它。
  • @Adam 出于某种原因,即使我将其标记为代码也无法正确显示
  • add an item of type group or user 是什么意思?您的意思是,如何添加整个 &lt;control&gt; 节点或仅将单个 &lt;type&gt; 添加到现有的 &lt;control&gt;

标签: xml delphi delphi-2010 ixmldomdocument


【解决方案1】:

1。如何修复 XPath 表达式?

其中任何一个都将修复查询:

1) 创建dom后添加以下行:

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

2) 更好的是,您可以更明确地说明您正在创建的解析器版本,并将您的构造行替换为:

Doc := CoDOMDocument60.Create; 

如果查询没有找到任何东西,Node 将为空。

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;

【讨论】:

  • 恐怕这些都无法解决 XPath 表达式中未转义的反斜杠。
  • 如果我进行这些更改中的任何一个,所有四个查询都会按预期工作。我错过了什么吗?
  • +1,对不起,我的错!我已经在我的代码的另一部分对其进行了测试......关于CoDOMDocument60的部分,CreateOleObject('Msxml2.DOMDocument.6.0')也是如此。
  • 删除的帖子图片是最好的部分。 :)
  • +1 经过测试,运行良好!特别感谢 TLama 的所有努力!
【解决方案2】:

这个答案总结了我在澳大利亚德尔福用户组博客"Dances with XML" 上的条目。如果您需要更多详细信息,请参阅它。

通过 XML 访问节点

您正朝着正确的方向前进,尝试利用 XPATH 作为访问和导航 XML 文档的简单机制。只是您的实现需要一些改进。演示代码如下所示。

Q1 如何轻松检查给定对象是否存在?

使用带有 XPATH 表达式的“in”运算符,以及引用的“Dances with XML”实用程序单元。例如,使用您提供的输入文档,此代码片段测试是否 一个控制节点存在一个

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;

【讨论】:

  • +1,但我更喜欢这样做而不使用额外的单位/第三方的东西,所以我接受了另一个答案。
猜你喜欢
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多