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
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>
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');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With