Soap-server returns the answer sometimes with xml-tag 'DELIVERY_DATE', and sometimes without it. How to write an if-condition to distinguish them, only without creating an xml-document , directly from the returned soap-response?

I tried this:

for i := 0 to FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes.Count - 1 do begin strCreate_Date:=FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['CREATE_DATE']; //if (FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].NodeName='DELIVERY_DATE') then ... if (FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes.FindNode('DELIVERY_DATE')<>Nil) then strDelivery_Date:=FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['DELIVERY_DATE']; else ; CDSGetBuyerWaybills.Append; CDSGetBuyerWaybills.FieldByName('create_date').AsString:=strCreate_Date; CDSGetBuyerWaybills.FieldByName('delivery_date').AsString:=strDelivery_Date; CDSGetBuyerWaybills.FieldByName('activate_date').AsString:=strActivate_Date; CDSGetBuyerWaybills.Post; end; 

but he never finds the tag and goes to else, both statements are ignored in the loop, if I write this:

 if (FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes.FindNode('DELIVERY_DATE')<>Nil) then... 

or so:

 if (FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].NodeName='DELIVERY_DATE') then ... 

and in xml the 'DELIVERY_DATE' tag is definitely there.

Soap-response has the form:

 <?xml version="1.0"?> <WAYBILL_LIST xmlns=""> <WAYBILL> <ID>206405566</ID> <TYPE>2</TYPE> <CREATE_DATE>2015-09-29T12:10:53</CREATE_DATE> <TRANSPORT_COAST>0</TRANSPORT_COAST> <DELIVERY_DATE>2015-10-03T10:34:43</DELIVERY_DATE> <STATUS>2</STATUS> <ACTIVATE_DATE>2015-09-29T12:10:55</ACTIVATE_DATE> <FULL_AMOUNT>279.99</FULL_AMOUNT> <CAR_NUMBER>UJU991</CAR_NUMBER> <WAYBILL_NUMBER>0198315109</WAYBILL_NUMBER> <CLOSE_DATE>2015-10-03T10:34:43</CLOSE_DATE> <S_USER_ID>26461</S_USER_ID> <BEGIN_DATE>2015-09-29T12:10:53</BEGIN_DATE> </WAYBILL> <WAYBILL> <ID>207247983</ID> <TYPE>2</TYPE> <CREATE_DATE>2015-10-03T12:20:09</CREATE_DATE> <TRANSPORT_COAST>0</TRANSPORT_COAST> <STATUS>1</STATUS> <ACTIVATE_DATE>2015-10-03T12:20:11</ACTIVATE_DATE> <FULL_AMOUNT>279.56</FULL_AMOUNT> <CAR_NUMBER>YPY088</CAR_NUMBER> <WAYBILL_NUMBER>0199129044</WAYBILL_NUMBER> <S_USER_ID>26461</S_USER_ID> <BEGIN_DATE>2015-10-03T12:20:09</BEGIN_DATE> </WAYBILL> </WAYBILL_LIST> 
  • What does it mean without creating an xml document if you already have one? You are accessing XMLNode. - Alexander Petrov
  • @AlexanderPetrov, I do not create an xml document anywhere, Soap-response itself contains a ready-made xml document (except for the header-a), from where I read. - Delphi159 1:21 pm
  • So work with an existing xml document. No need to work with the string. - Alexander Petrov

2 answers 2

It is most correct to check the already received XML for the tag.

 If Pos('<DELIVERY_DATE>', XmlResponse) > 0 then // значит тэг есть. ... else // тэга нет. 

PS I saw the condition without creating an XML document . Counterquestion; and why? Why complicate things? Why poke around in a SOAP envelope and pile up extra lines of code?

For each task there is an elegant solution. And this one too. The grace here will be to find the tag is already in the answer . In this case, the XML file itself can not be rushed to write to the disk, and tag search operations can be performed in memory.

UPDATE
I think the problem may be in a variable that is declared as var . In this case, I would advise you to declare the intermediate variable var s: string and assign it the value XMLNode.Xml . Thus, the XML text is simply copied to the variable s and further manipulations can be made with it.

UPDATE 2
As it turned out in the chat, you need to correctly check the presence of the <DELIVERY_DATE> element, without causing exceptions and without resorting to direct parsing of lines, which is unwise in this situation. Thus, the methods proposed above are attempts to give an answer to an incorrectly formulated question .

In order to correctly check the presence of an element through MSXMLDOM, you need to use the FindNode() method which is available for the IXMLNodeList collection. In the code, it will look like this (for clarity, I used with..do ):

 with FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i] do //сначала обязательно проверим наличие элемента //чтобы потом не попытаться обратиться к неициализированному объекту и не вызвать AV if ChildNodes.FindNode('DELIVERY_DATE') = nil then //элемента не существует ShowMessage('There is no DELIVERY_DATE element in this Waybill!') else //элемент существует begin ... end; 

If you look at the nesting hierarchy of objects, then everything looks very logical:

  • XMLNode in the code above means the entire Waybills collection (i.e., <WAYBILL_LIST> )
  • Next, we run in a loop through all the child nodes of WAYBILL , “look in” them and look for the elements we need in their child nodes ( ChildNodes )
  • Finding the desired item is done via FindNode('DELIVERY_DATE') . If the item is not found, then the value will be nil .

Then everything is very easy.

And on dessert: WHY DID POS () NOT WORK?
Because all sorts of things like ChildValues['DELIVERY_DATE'] do not return a string , but System.OleVariant which cannot be implicitly converted to a string. For this reason, an exception was thrown.

UPDATE 3
Here is a screen of fully working code. Which fulfills the tag "non-spawning" and gives it to the log below.

enter image description here

UPDATE 4
Here is the code that does not just answer the question, but also solves the specific problem of the author-programmer. Which he must decide himself, not us.

 //показываем что вне зависимости от наличия/отсутствия тэга //мы будем добавлять записи в DataGrid CDSGetBuyerWaybills.Append; if FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildNodes.FindNode('DELIVERY_DATE') = nil then begin //логируем информацию о том, что WB без DELIVERY_DATE Memo.Lines.Add ('There is no DELIVERY_DATE node in this WB with ID=' + IntToStr(i)); //произвольно устанавливаем значение переменной strDelivery_Date strDelivery_Date := 'active'; end else //иначе!!! (если тэг есть) begin strDelivery_Date:=FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['DELIVERY_DATE']; strYear:=copy(strDelivery_Date,1,4); //за такое преобразование даты strMonth:=copy(strDelivery_Date,6,2); //нужно нещадно бить розгами! strDay:=copy(strDelivery_Date,9,2); strDelivery_Date:=strDay+FormatSettings.DateSeparator+strMonth+FormatSettings.DateSeparator+strYear; end; //теперь, когда все условия проверены и параметры установлены //начинаем запиливать значения в DataGrid: CDSGetBuyerWaybills.FieldByName('ID').AsString := FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['WAYBILL_NUMBER']; CDSGetBuyerWaybills.FieldByName('amount').AsString :=VarToStrDef(FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['FULL_AMOUNT'], ''); CDSGetBuyerWaybills.FieldByName('seller').AsString := VarToStrDef(FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['SELLER_NAME'], ''); CDSGetBuyerWaybills.FieldByName('create_date').AsString:=strCreate_Date; CDSGetBuyerWaybills.FieldByName('delivery_date').AsString:=strDelivery_Date; CDSGetBuyerWaybills.FieldByName('activate_date').AsString:=strActivate_Date; //в самом конце проверяем статус if FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['STATUS']=1 then CDSGetBuyerWaybills.FieldByName('status').AsString:='active' else CDSGetBuyerWaybills.FieldByName('status').AsString:='ended'; //и наконец постим все это в базу CDSGetBuyerWaybills.Post; 
  • Interface Unknown, tried this: 1) If Pos ('<DELIVERY_DATE>', FromServ.get_buyer_waybillsResult.XMLNode.Text)> 0 then .... displays: "Element Waybill-list doesn't contain a single text node" 2) If Pos ('<DELIVERY_DATE>', FromServ.get_buyer_waybillsResult)> 0 then ... displays: "there is no overload version of the pos" - Delphi159
  • FromServ - is that what we have? Component? - Interface Unknown
  • ToServ, FromServ-variables of a procedural type. var WBS: WayBillsSoap; ToServ: get_buyer_waybills; FromServ: get_buyer_waybillsResponse; ........ WBS: = GetWayBillsSoap (false, '', Fmain.HTTPRIO1); ToServ: = get_buyer_waybills.Create; FromServ: = WBS.get_buyer_waybills (ToServ); - Delphi159
  • in FromServ.get_buyer_waybillsResult, I get a pure XML response and freely manipulate it. for example: Memo.Text: = FromServ.get_buyer_waybillsResult.XMLNode.Xml; or strDelivery_Date: = FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes [i] .ChildValues ​​['DELIVERY_DATE']; those. I can get any tag from it, but I can’t write an operator how to find out the absence of a tag! - Delphi159
  • No need to write code in the comments. It is better to edit the question and add this code there. And also what these functions return. - Interface Unknown

I myself decided the question differently:

  if (FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['DELIVERY_DATE']<>Null) then strDelivery_Date:=FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].ChildValues['DELIVERY_DATE'] else; 

The code works correctly (in the figure, one deliver_date is empty), although the condition is different (if ... <> Null).

enter image description here

As for the code that offered Interface Unknown:

  if FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i].childnodes.FindNode('DELIVERY_DATE') = nil then //элемента не существует ShowMessage('There is no DELIVERY_DATE element in this Waybill!') else //элемент существует begin ... end; 

also works correctly! Thanks to him!

  • I'm shocked. I gave the correct answer to the question that you copied exactly in your “answer” ...))) And I didn’t see anything new, you say? - Interface Unknown
  • Maybe you just need an urgent operation to transplant hands back into the shoulders? Everything works for me :-) Screen faith, and normally and properly formatted code in my XE4 :-) - Interface Unknown
  • I did not offer this code. You, apparently, have not watched something. I used the instruction with FromServ.get_buyer_waybillsResult.XMLNode.ChildNodes[i] do where ChildNodes[i] is all the Waybills! - Interface Unknown