Thursday, May 5, 2011

Delphi - Invalid namespace URI in IXMLNode

I am trying to parse a response from a SOAP web service, but part of the data has an invalid xmlns element and I think it is causing me no end of trouble.

The part of the XML that I am working with is as follows.

<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <ResponseData xmlns="http://www.example.com/WebServices/Schemas/1">
     <ResponseDataResult>
      <Messages xmlns="http://www.example.com/WebServices/Schemas/2">
       <Message>...</Message>
      </Messages>
     </ResponseDataResult>
     ...
    </ResponseData>
</soap:Body>

The xmlns URI in the soap:Body node is OK, its the one in ResponseData that is invalid, it points to a none existent document. It should be noted that the web service is not under my control so fixing this is out of the question :(.

my Delphi (2007) code look, at present, something like this.

var l_tmp,l_tmp2,FSOAPBody:IXMLNode;

begin
    ...

    FSOAPBody := FSOAPEnvelope.ChildNodes.FindNode('Body','http://schemas.xmlsoap.org/soap/envelope/');
    //returns the xml above.
    if (FSOAPBody = nil) then exit;

    l_tmp := FSOAPBody.ChildNodes.FindNode('ResponseData','');
    if (l_tmp = nil) or (not l_tmp.HasChildNodes) then exit;

    l_tmp2 := l_tmp.ChildNodes.FindNode('ResponseDataResult','');

    ...
end;

In the above code, I have had to add the blank namespace url to the FindNode('ResponseData','') code as with out it, it will not find anything and returns nil, with it however it reutrns the expected XML.

The problem is that the next find node (ChildNodes.FindNode('ResponseDataResult','')) raises an access violation when trying to access the ChildNodes of l_tmp, I can look at the xml using l_tmp.xml and see that it is the XML I would expect.

I suspect that it is due to the missing namespace, so I have tried to remove it, but get more errors saying it is a read-only attribute.

Is there anyway to remove the xmlns attribute or select nodes regardless of there NS? or am I going about this wrong?

From stackoverflow
  • It is not expected that all namespace URIs refer to actual resources. They are used primarily as unique identifiers so XML from multiple sources can use the same names without interfering with each other. They are not required to point to the schema that describes the valid element and attribute values for the namespace; XML doesn't even require that such a schema exist.

    If you want to search for elements without regard for namespace, then call the one-argument version of FindNode.

    l_tmp := FSOAPBody.ChildNodes.FindNode('ResponseData');
    

    The two-argument version requires a namespace, and when you specify an empty string, it means you're requesting only nodes that have empty namespaces. Since you apparently know what the namespace is, you could call the two-argument version anyway, just like you used it to get the body element:

    l_tmp := FSOAPBody.ChildNodes.FindNode('ResponseData',
               'http://www.example.com/WebServices/Schemas/1');
    

0 comments:

Post a Comment