IXMLDocument 的Node属性和DocumentElement属性区别

本文介绍了在使用IXMLDocument时遇到的关于Node属性和DocumentElement属性的区别。当尝试读取不存在的节点时,如果Options属性包含doNodeAutoCreate,会自动创建新节点。同时,XML文档的Node是整个文档的根节点,包含DocumentElement等子节点,而DocumentElement是实际数据的根节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天写一个Xml配置的读写类,遇到了几个问题,记录如下。

1)读一个并不存在的节点竟然不出问题?

用了一个很简单的 xml 文件,如下 

<!-- test.xml -->
<?xml version="1.0" encoding="GB2312"?>
<value>
   
<v> abc def ghi </v>
</value>

读写代码如下:

// 竟然没有delphi的代码模版?kao

procedure TForm1.btnReadClick(Sender: TObject);
var
  N: IXMLNode;
  St: TStringList;
  I: Integer;    
begin
  St :
=  TStringList.Create;
  
try

    St.Text :
=  edtNodeName.Text;
    St.Text :
= StringReplace(St.Text, '/', #13#10, [rfReplaceAll]);  // 输入的Node序列格式为"ParentNode/SubNode",

    N :=  xmldoc1.DocumentElement;
    
for I := 0 to St.Count - 1 do

    begin
      N :
=  N.ChildNodes.Nodes[St[I]];
      
if N =
 nil then
        MessageDlg(Format(
'无此节点 "%s"', [St[I]]), mtError, [mbOK] , 0
);
    end;
    
if N <>
 nil then
      
if
 not N.IsTextElement then
      begin
        MessageDlg(
'not text node', mtInformation, [mbOK], 0
);
        edtResult.Text :
= Format('%s is %s'
, [N.NodeName, NodeTypeToStr(N.NodeType)]);
      end
      
else

        edtResult.Text :
=  N.Text;
  
finally

    St.Free;
  end;
end;

该代码从名为 btnNodeName  的编辑框中读取Node的名字,支持多层级,如要读取上面的test.xml文件的v节点的值,只要输入 “value/v” (写这段代码时是这样想的,但是这样想是错误的,后面有说明).

但是,测试的时候,发现总是报 v 不是 TextElement,百思不得其解,后来无意中发现原来执行时打开的是另外一个xml文件,但是该xml文件的结构完全不一样,压根就没有 value 和 v 节点,怎么还能够读取到这两个节点呢?

仔细看了一下帮助,在对 IXMLNodeList.Nodes属性的解释中,发现了这段说明:

If IndexOrName does not identify a node in the list, and if the document that contains this node list's parent includes doNodeAutoCreate in its Options property, then the node list tries to create a new node with the name specified by IndexOrName. If the node list can't create the new node, it raises an exception.

原来,如果 Nodes 属性的参数 IndexOrName(为结点名时) 所指定的节点不存在,并且 其所属的 IXmlDocument 的 Options 属性包含了doNodeAutoCreate值,则会自动创建一个新的节点,命名为 IndexOrName 的值,所以才会出现读取不存在的节点也不会出错的现象,而且因为该节点加入后,没有设置值,所以类型是ntElement,而不是ntText,所以会报不是 TextElement。我们只要在创建IXmlDocument对象后加入下面的代码就可避免这种情况:

xmlDoc :=  TXmlDocument.Create(nil);
xmlDoc.Options :
= xmlDoc.Options - [doNodeAutoCreate];

2)value 节点不存在?

修正了上面的问题之后测试,edtNodeName 输入为“value/v”,报错,提示“value”节点不存在,奇怪,怎么会不存在,这回打开的确实是test.xml文件啊。查看代码,发现 TXMLDocument 读取 DocmentElement 属性是这样实现的:

function TXMLDocument.GetDocumentElement: IXMLNode;
begin
  CheckActive;
  Result :
=
 nil;
  
if
 Node.HasChildNodes then
  begin
    Result :
=
 Node.ChildNodes.Last;
    
while Assigned(Result) and (Result.NodeType <> ntElement) do

      Result :
=  Result.PreviousSibling;
  end;
end;

这个 Node 是个什么东西?继续查看有关 Node 的代码,并且翻看帮助,帮助是这样说的:

Read Node to access the document node for the XML document. The document node represents information about the entire document. It may have several child nodes, which represent comments, processing instructions, and which include the DocumentElement node that acts as the root of the data hierarchy.

原来 Node 才是 xml 文档的真正根节点,而 DocumentElement 只是我们的xml文件的内容的根节点,是 Node 的子节点,对于上面的 test.xml 来说, DocmentElement 就是表示 value 节点,而在上面的代码中,我们实际上读取的是“value/value”节点,难怪会不存在,把上面的

N := xmldoc1.DocumentElement;

改为

N := xmldoc1.Node;

就 OK 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值