views:

47

answers:

2

I used the XML Binding Wizard to create a descendant of TXMLDocument. The files generated by this class would declare the namespace in the root node and create just plain, unadorned nodes for the rest of the document.

<?xml version="1.0"?>
<RootNode xmlns="URL" xmlns:xsi="URL" xsi:schemaLocation="URL">
    <SomeNode>
        <AnotherNode>Value</AnotherNode>
    </SomeNode>
</RootNode>

I've had no trouble reading or validating this at all. However, the third party processor where these files are sent (which hadn't had any problems up to this point) informed me that their parser is suddenly incapable of processing the file unless each node has the namespace prefixed.

<?xml version="1.0"?>
<NS:RootNode xmlns:NS="URL" xmlns:xsi="URL" xsi:schemaLocation="URL">
    <NS:SomeNode>
        <NS:AnotherNode>Value</NS:AnotherNode>
    </NS:SomeNode>
</NS:RootNode>

How do I accomplish this with my TXMLDocument descendant? I hope it doesn't involve hand editing 10000 lines of generated code.

A: 

http://stackoverflow.com/questions/2803063/add-namespace-prefix-to-xml-using-xsl

The accepted answer shows how XSL can be used to add namespace prefixes.

mjustin
+1  A: 

Ok, the solution took a long time to discover but was surprisingly simple.

The code generated by XML Data Binding Wizard will create xml using the default namespace. You can see this my examining the Get, Load and New functions in the generated unit. All three make calls to GetDocBinding, passing in TargetNamespace as the finally parameter. TargetNamespace is a global constant string with the URI extracted from the schema or xml document you fed to the Binding Wizard.

Because TargetNamespace is assigned to the root element as the default namespace no child elements will have a prefix. To add a prefix to all the child elements use the following code:

FDocumentName := NewDocumentName; // or GetDocumentName or LoadDocumentName
FDocumentName.AttributeNodes.Clear; //Gets rid of the default namespace
FDocumentName.DeclareNamespace('ns', TargetNamespace);

There appears to be a bug that causes the first child element and its child elements to still not have the prefix after doing the above. Calling

FDocumentName.AddChild('FirstElement', TargetNamespace);

just before accessing that element appears to work around it.

codeelegance
If this is the solution, mark this as the solution. About the bug you found: add a report to qc.embarcadero.com
The_Fox
@The_Fox have to wait 24 hours before you can accept your own answer to a question.
codeelegance