Delphi:从父节点获取XML子节点属性

4

我正在尝试在Delphi中编写XML。

如果我给一个节点添加xmlns属性,那么该节点的子节点也会显示这个属性,但是是空的。我如何防止子节点显示该属性?

我使用以下代码进行测试:

procedure TForm2.Button1Click(Sender: TObject);
var
  RootNode, CurNode, PmtNode, PmtDetNode : IXMLNODE;
  I:Integer;
begin
   SepaDoc := Newxmldocument;
   SepaDoc.Encoding := 'utf-8';
   SepaDoc.Options := [doNodeAutoIndent];
   RootNode := SepaDoc.AddChild('Document');
   CurNode := RootNode.AddChild('Child1');
   CurNode.Attributes['xmlns'] := 'apenootje';
   CurNode := CurNode.AddChild('Child2');
   CurNode := CurNode.AddChild('Child3');
   SepaDoc.SaveToFile('D:\indir\testsepa.xml');
end;

这将导致以下XML结果。
<?xml version="1.0" encoding="UTF-8"?>
-<Document>   -<Child1 xmlns="apenootje">
    -<Child2 xmlns="">
       <Child3/>
     </Child2>
    </Child1>    
  </Document>

感谢Rob Nowee。
2个回答

7

由于Child1的子元素没有使用相同的命名空间,因此必须进行未声明处理,这就是Child2持有空(默认)命名空间的原因。

这被称为命名空间未声明

当一个元素携带属性xmlns=""时,该元素及其后代的默认命名空间将恢复为“无命名空间”:也就是说,未加前缀的名称不属于任何命名空间。

XML命名空间1.1还引入了未声明其他命名空间前缀的选项。例如,如果属性xmlns:p=""出现在元素上,则命名空间前缀p不再适用(因此不能在该元素或其后代中使用),除非通过另一个命名空间声明重新引入它

也就是说,修复很简单;在所有后续子节点中包含命名空间:

program SO20424534;

{$APPTYPE CONSOLE}

uses
  ActiveX,
  XMLdom,
  XMLDoc,
  XMLIntf,
  SysUtils;

function TestXML : String;

var
  RootNode,
  CurNode    : IXMLNODE;
  Doc        : IXmlDocument;
  ns         : String;

begin
 Doc := Newxmldocument;
 ns := 'apenootje';
 Doc.Encoding := 'utf-8';
 Doc.Options := [doNodeAutoIndent];
 RootNode := Doc.AddChild('Document');
 CurNode := RootNode.AddChild('Child1');
 CurNode.DeclareNamespace('', ns);
 CurNode := CurNode.AddChild('Child2', ns);
 CurNode := CurNode.AddChild('Child3', ns);
 Result := Doc.XML.Text;
end;
    
begin
  try
   CoInitialize(nil);
   try 
    Writeln(TestXML);
   finally
    CoUninitialize;
   end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
 Readln;
end;

输出:

<?xml version="1.0"?>
<Document>
  <Child1 xmlns="apenootje">
    <Child2>
      <Child3/>
    </Child2>
  </Child1>
</Document>

1
嗨@user3074489,很高兴听到这个好消息。你可以通过接受这个答案来感谢我 :) - whosrdaddy
代码正在运行。而且 Remy 的解释 帮助我理解了这个问题。 - yonojoy

3

在使用命名空间之前必须声明它。简单添加一个xmlns 属性不足以让DOM知道该命名空间的存在是不正确的方式。使用IXMLNode.DeclareNamespace()来声明,例如:

CurNode := RootNode.AddChild('Child1');
CurNode.DeclareNamespace('', 'apenootje');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接