-4

I'm reading a XML file and get a i/o error when reading the node <kamerkant/>. I use the following statement for reading the node:

Lclvalue := Sel.Selectnode('//Gordijn[1]/Kamerkant[1]/node()').nodeValue

XML

<Gordijn>
    <StofNaam>Aroma 211004</StofNaam>
    <Kleur>211</Kleur>
    <Gordijnsoort>streepgordijn</Gordijnsoort>
    <Vertrek>Woonkamer voor</Vertrek>
    <Kamerkant/>
    <Hoogte>100.0</Hoogte>
</Gordijn>
Arioch 'The
  • 15,799
  • 35
  • 62
user3552264
  • 147
  • 1
  • 2
  • 12

1 Answers1

3

Well, what else do you want to get with such a data and such a request ?

With the request "//Gordijn[1]/Kamerkant[1]/node()" you literally ask for "all the nodes withing Kamerkant[1]"

But your Kamerkant is an empty node - it contains ZERO nodes inside it. So the result of your request - to extract nodes from the container lacking nodes inside - can only be NULL or empty set having nothing in it. And what is the nodeValue of nothing, of the non-existent object? It is error to try to get something out of nothing, don't you think?

Just use one of the XPath calculators I mentioned, enter there your XML sample and run evaluation for the requests

  • //Gordijn[1]/Kamerkant[1]/node()
  • //Gordijn[1]/Kamerkant[1]
  • //Gordijn[1]/node()

See the difference yourself.

That said, when you use SQL - you have to debug your query and data in some generic non-Delphi SQL tool, and only after that when you got the correct tested SQL request to copy it into your Delphi code.
Same applies to XPath - you better first use XPath calculators to debug XPath requests outside of Delphi and only when succeed you are to replant the tested correct XPath into your Delphi code.


According to

you maybe (depending on variety of ur source data) can use something like

  Lclvalue := Sel.Selectnode('//Gordijn[1]/Kamerkant[1]');
  if LclValue.hasChildNodes then begin
     LclNodes := LclValue.childNodes;  
     for i := 1 to LclNodes.length do begin
         LclValue := LclNodes.item[i];
         ... process LclValue....
     end;
  end;
  LclValue := nil; // release memory you need no more
  LclNodes := nil;

That said, is do not think that is really the most efficient way to do it, it clearly does not fit into set-based XPath worldview. To me it looks like "indexed sequential access method" applied over SQL datasource.

So to me it looks that you do not have to select one node in particular, less so the first node ( those "[1]" in your query - why??? ).

You really try to get the list of ALL the nodes that maybe are interesting to you and prepare for the event there would be none.

For example, the I/O error you get - it MAY (or may not, I do not know, check the docs) be exactly the way of your xml parser to tell "nothing found, empty results".


I open www.google.com and I type there "stackoverflow xpath check if node is empty"

That said, there are different XPath versions and different XPath engines - so whether the XML parser of your code can use those methods only you can determine.


But at very least the following - not very efficient also - seems to be possible;

  LclNodes := Sel.Selectnodes('//Gordijn/Kamerkant'); // all the Kamerkants
  // MAYBE check for error if XML source has no single Kamerkant, 
  // i can only GUESS how that maybe would be represented
  // you can CHECK it or READ DOCS

  for i := 1 to LclNodes.length do begin 
  // i GUESS LclNodes.length=0 for no Kamerkants data input - i may be badly wrong
    LclValue := LclNodes.item[i]; // some Kamerkant   
    if LclValue.hasChildNodes then begin
       LclKamerkantNodes := LclValue.childNodes;  
       for j := 1 to LclKamerkantNodes.length do begin
           LclValue := LclKamerkantNodes.item[j];
           ... process LclValue....
       end;
    end;
  end;
  LclValue := nil; // release memory you need no more
  LclKamerkantNodes := nil;
  LclNodes := nil;

In the latter code i ASSUME that in general XPath's attitude to SelctNode/SelectNodes is the same as SQL's attitude to singular/general SELECT operation. The former is required to produce exactly 1 row of result, less than 1 or more then 1 are error conditions. The latter gives you a set of rows, that might be empty or might be multiple as well as singular, so you have a flexibility to code for those cases. The former is laconic but fragile with regard to unexpected input data. The latter is much more flexible but also much more tedious and verbose. The choice definitely is yours. But judging from your confusion w.r.t I/O Error - your original choice to use hardcoded singular select maybe was unlucky one.

Community
  • 1
  • 1
Arioch 'The
  • 15,799
  • 35
  • 62
  • Hi Arioch, Thanks for the answer. But how do i check if a Node is not empty? – user3552264 Jun 29 '15 at 10:24
  • 1
    That is another question, don't you think ? And it is not even about Delphi and about XML/XPath in general For the certain question you asked I guess you got the answer. So - get yourself your favourite XPath calculator, open tutorals/manuals, open google - and experiment. PS: with your particular sample - just do not call ".nodeValue" - get some result and evaluate what is it before. I do not know what type you get after Sel.Selectnode and what properties/methods it has, but I think you can check it. – Arioch 'The Jun 29 '15 at 10:25
  • I open www.google.com and I type there "stackoverflow xpath check if node is empty" - top two results are http://stackoverflow.com/questions/15909348 and http://stackoverflow.com/questions/13703478 /// that said, there are different XPath versions and different XPath engines - so whether the XML parser of your code can use those methods only you can determine. – Arioch 'The Jun 29 '15 at 10:29
  • Sel is a IDomNodeSelect. I can't see a property or method other than nodevalue that i can use.. – user3552264 Jun 29 '15 at 10:30
  • just evaluate in debugger, maybe it would be nil. or maybe other properties would give some specific values. – Arioch 'The Jun 29 '15 at 10:31
  • Ok. I wil look further if i can find a method that i can use. – user3552264 Jun 29 '15 at 10:31
  • then you may also do request for "//Gordijn[1]/Kamerkant[1]" and work with it for emptiness check – Arioch 'The Jun 29 '15 at 10:31
  • "Sel is a IDomNodeSelect " - I did not asked for Sel! I asked for the featues of .Selectnode result !!! – Arioch 'The Jun 29 '15 at 10:33
  • then use request that does not give you I/o error and work with it. Or check for I/o error - it MAY (or may not, I do not know, check the docs) be exactly the way of your xml parser to tell "nothing found" – Arioch 'The Jun 29 '15 at 10:34
  • Sorry i don't understand what you mean exactly?. – user3552264 Jun 29 '15 at 10:35
  • i guess you have to get Kamerkant itself, not its children, and then call http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/xmldom_IDOMNode_hasChildNodes.html – Arioch 'The Jun 29 '15 at 10:35
  • you call a function .Selectnode - that function gives you result of some type, with that result you can work, so what is the type of the result of .Selectnode return value? that result (and the type of the result, not of Sel) is what you work with. – Arioch 'The Jun 29 '15 at 10:36
  • Ok. Thank you. Thanks. – user3552264 Jun 29 '15 at 10:37
  • 2
    @user3552264 This would be so much easier if you would supply some real detail in the question as has been asked. Why won't you include an MCVE in the question. You could do it in about 20 lines of code. I urge you to make more effort when asking so that you can get more informed answers. Ask better questions, get more relevant and useful answers. – David Heffernan Jun 29 '15 at 10:41
  • 2
    It's not too late to do it this time. You can edit the question. This is a wiki. – David Heffernan Jun 29 '15 at 10:45
  • @user3552264 in general - that is the good thing adding the missing details relevant to your particular question by editing the question - that is ENHANCING the GENUINE question. And it is bad thing to extend and divert the question itself, that is SUBSTITUTING ANOTER question. The former behaviour is contribution and cooperation, the latter it not. – Arioch 'The Jun 29 '15 at 10:57