Monthly Archives: December 2013

Delphi Cross-platform XML: Beware the XML parser differences

When you are doing cross-platform Delphi with XML, be very careful about the XML parser.  I just got bit by a treacherous behavior difference between XML parsers.  It works perfectly fine in Windows (using the default MS XML parser), but fails miserably on other platforms (using the ADOM XML parser).

It turns out that the ADOM XML parser has a bug (well, I think it is a bug) that its implementation of the IXMLNode.HasAttribute and IXMLNode.Attributes[named string] functions fail when the attributes have namespaces (for example, ‘xlink:href’).  I had code in my software that looked for attributes by name:

if Node.HasAttribute(Name) then
  result := Node.Attributes[Name]

This code works perfectly using the MS XML parser but fails miserably with the ADOM XML parser and attributes with namespaces.  When you call HasAttribute and Attributes[Name] using the ADOM XML parser, it assumes a namespace equal to ”.  Then, its code to find the attribute checks the namespace and attribute name and fails.  For example, ‘xlink:href’ will fail because it compares a blank namespace string with ‘http://www.w3.org/1999/xlink’.  Note that this means that you will fail even if you only passed in ‘href’.

Ideally, the ADOM implementation would either ignore the namespace if you are not asking for the namespace, or it would detect that your name contains a namespace and would find the NamespaceURI.  However, until then,to make it work, you need to look for the NamespaceURI yourself:

if NamespaceTag <> '' then
   NamespaceTag := Node.FindNamespaceURI(NamespaceTag);
 if Node.HasAttribute(Name, NamespaceTag) then
  result := Node.GetAttributeNS(Name, NamespaceTag)

So beware of XML parser differences!

Working on Windows for debugging is just so much faster and smoother, I recommend testing the Windows version of your XML application using the ADOM XML parser.  The following code will force the Windows version to use the ADOM XML parser:

uses
  xmlintf, adomxmldom, xmldom;
var
  XML: TXMLDocument;
<span style="font-size: 0.857142857rem; line-height: 1.714285714;">begin
</span>  XML := TXMLDocument.Create(nil);
  XML.DOMVendor := GetDOMVendor(adomxmldom.sAdom4XmlVendor);
  XML.LoadFromFile(Filename);
&lt;snip&gt;

Hope this helps someone else!  Happy CodeSmithing!