user3074489
user3074489

Reputation: 41

delphi xmlchildnode gets attribute from parent

I am trying to write an xML in Delphi.

If I gife a node a xmlns attribute, the child node of that node shows the attribute also but then empty. How can I prefent that the child node shows the attribute?

I tested with the following code

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;

This result in the following XML

<?xml version="1.0" encoding="UTF-8"?>
-<Document>   -<Child1 xmlns="apenootje">
    -<Child2 xmlns="">
       <Child3/>
     </Child2>
    </Child1>    
  </Document>

Thanks Rob Nowee

Upvotes: 4

Views: 2593

Answers (2)

whosrdaddy
whosrdaddy

Reputation: 11860

Since the child elements of Child1 don't carry the same namespace, it must be undeclared and that's the reason that Child2 is holding the empty (default) namespace.

This is known as Namespace undeclaration

When an element carries the attribute xmlns="", the default namespace for that element and its descendants reverts to "no namespace": that is, unprefixed names are considered not to be in any namespace.

XML Namespaces 1.1 also introduces the option to undeclare other namespace prefixes. For example, if the attribute xmlns:p="" appears on an element, the namespace prefix p is no longer in scope (and therefore cannot be used) on that element or on its descendants, unless reintroduced by another namespace declaration

That being said, the fix is simple; include the namespace on all subsequent child nodes:

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;

Output:

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

Upvotes: 7

Remy Lebeau
Remy Lebeau

Reputation: 596256

You have to declare a namespace before you can use it. It is not enough to simply add an xmlns attribute manually, which is not the correct way to let the DOM know about the existence of the namespace. Use IXMLNode.DeclareNamespace() for that instead, eg:

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

Upvotes: 3

Related Questions