Confusing with xml.XQL in a xml document with <soap:Body> tag

I’m trying to parse a xml document from a web service. It’s a simply one but I’m new with XML parsing.

The xml is like this:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
	<soap:Header>
		<HeaderInfo
			xmlns="http://web.com/">
			<fecha>2020-09-02T20:55:04.2882491-03:00</fecha>
			<id>4.0.0.0</id>
		</HeaderInfo>
	</soap:Header>
	<soap:Body>
		<DummyResponse
			xmlns="http://website.com/">
			<DummyResult>
				<AppServer>OK</AppServer>
				<DbServer>OK</DbServer>
				<AuthServer>OK</AuthServer>
			</DummyResult>
		</DummyResponse>
	</soap:Body>
</soap:Envelope>

I’m trying to get values from AppServer, DbServer and AuthServer. My code is this:

dim xml as new XmlDocument
xml.LoadXml(xmlFile)

Dim nodesBody As XmlNodeList
Dim nodeSoapBody as xmlNode

nodesBody=xml.DocumentElement.XQL("soap:Body")
if nodesBody>0 then nodeSoapBody= nodesBody.Item(0)

Here I get the soap:Body as a node. What I’m not been able to get is the values inside . I’ve tryed with all this variants with no luck:

dim nodes as XmlNodeList
dim node as xmlNode

nodes=nodeSoapBody.XQL("//FEDummyResponse")  //1º try
nodes=nodeSoapBody.XQL("//FEDummyResult")        //2º try
nodes=nodeSoapBody.XQL("//AppServer")                  //3º try
nodes=nodeSoapBody.XQL("FEDummyResponse")    //4º try

I see using XQL inside a Node is not the same as using in a xml file. Am I right?

If I use:

nodeSoapBody.FirstChild.FirstChild.FirstChild

I get the AppServer Node but nodeSoapBody.FirstChild.FirstChild.FirstChild.Name don’t get the value “Ok”.
Could somebody help me with this newee question?

And other related questions: What’s the difference in using xml.XQL("//variable") instead of xml.XQL(“variable”)?

Thanks a lot.

The issue seems to be how XML namespaces are dealt with
And I have to admit I’m not sure how to deal with this using XQL

with the following code

Dim xml As New XmlDocument
xml.LoadXml(kSoapReply)

Dim nodesBody As XmlNodeList
Dim nodeSoapBody As xmlNode

nodesBody=xml.XQL("//DummyResponse")
If nodesBody.Length > 0 Then
  For i As Integer = 0 To nodesBody.Length - 1
    Dim node As XmlNode = nodesBody.Item(i)
    
    System.debuglog node.Name
  Next
End If

and a constant holding you original soap reply nothing is printed

IF I alter that reply to omit the xmlns attribute in DummyResponse so its like

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
	<soap:Header>
		<HeaderInfo xmlns="http://web.com/">
			<fecha>2020-09-02T20:55:04.2882491-03:00</fecha>
			<id>4.0.0.0</id>
		</HeaderInfo>
	</soap:Header>
	<soap:Body>
		<DummyResponse >
			<DummyResult>
				<AppServer>OK</AppServer>
				<DbServer>OK</DbServer>
				<AuthServer>OK</AuthServer>
			</DummyResult>
		</DummyResponse>
	</soap:Body>
</soap:Envelope>

then the code works as expected

usually for name spaces, like the ones defined in the soap header, you create a map and pass that to the XQL query as well
But in this case the namespace is hard code to a specific URL

Short of just writing code to walk through the nodes I’m not sure how the XQL of Xojo’s XML can be used with that kind of namespace

Try this:

nodesBody.item(0).FirstChild.firstChild.firstchild.firstChild.Value

(edit to add your variable names)
or:

nodeSoapBody.FirstChild.FirstChild.FirstChild.FirstChild.Value

It’s clunky but you get OK with it. Note there’s another FirstChild in there.

Faced with this in the past, I have resorted to throwing away the SOAP wrapper before I start.

Take the entire message as a string, and (using INSTR) throw away everything up to and including
"<soap:Body>"

Then throw away everything after and including "</soap:Body>"

What you have left is usually easily used with XQL

The problem is the unqualified name space in your node (xmlns=“http://website.com/”)
this lead XQL to don’t understand the tree. (it’s a bug)
If you remove the xmlns=“http://website.com/” everything works correctly

To use NS in XQL you have to add an array as second parameter, this array must be created as a sequence of namesSpace name and nameSpace URL. IE array(“soap”, “http://schemas.xmlsoap.org/soap/envelope/”) and so on.
Sometimes an array like ("", “”) can solve this kind of problems, but in your case neither ("", “”) nor ("", “http://website.com/”) seems to work.
If you remove xmlns=“http://website.com/” your code will work (using DummyResponse and not FEDummyResponse)

Thank you all for helping me with this. If I get this correct, the problem is that namespace <xmlns=“http://website.com/”> has no name, only the URI, is that correct? Maybe it should be something like this: xmlns:var1=“http://website.com/”?

Norman, I’ve tryed this and yes, it works and it confirm the problem is that line but I can’t code to specific remove this text because it could change with time.

Jeff, I’ve done this before with other XML files and it’s usefull. I could even just look for the value between “< AppServer >” and “< /AppServer >” with INSTR because in this case it will always be just one entry of this type but I wanted to learn the use of XML class. Maybe it’s not possibly with this XML and your solution is the most practical.

Antonio, I see, this is what I don’t entirely understand, the use of the map() array parameter. Could you explain it to me a little? What I’ve understand is that (in this case) I should use it like:

dim map() as String=array("xsd","http://www.w3.org/2001/XMLSchema","xsi","http://www.w3.org/2001/XMLSchema-instance","soap","http://schemas.xmlsoap.org/soap/envelope/")
nodes=xml.XQL("soap:Header",map())

What I don’t understand is when do I have to use it. In every XQL when a xml have namespaces on it whatever the tag is what I’m looking for? Why “nodes=xmlToParse.DocumentElement.XQL(“soap:Body”)” find the soap:Body tag without using the map()? I don’t have clear if I need to use for the entire xml o just to look inside a tag with namespaces on it.

Thanks you all again.

A name space should be like var1:“http://website.com
even if you never use the var1 name space (like in your case)
name spaces (obviously) are usefull to avoid colliding names from different sources (a document could be created by several tools and rules)

It is advisable to use the map array parameter if your xml has namespaces.

So you can remove the “local” namespace or declare it as var1…

A little tip: to read the AppServer value (and the others) instead of verify if the node exists and then if the text node exists and then take the value, you can search directly something like “AppServer/text()”
If the text node exists (xql lenght>0) then you have already the node and you can read its value.

Thanks Antonio, I’ll try that way so.