Hello again Johan
Not withstanding Bruceâs comment that you can easily see what nodes are present with xFiles, I can see you are wanting to validate that your received XML files are in a certain strict format before loading with xFiles.
Whereas line breaks (that are not within an element) are generally not significant in XML - these and indenting are more for human readability - in your case you want each element to be on a separate line.
Whereas elements can usually be in any order, you want your elements to be in a specified order.
Hence you are splitting on CRLF and then checking there are exactly 78 lines corresponding to 78 fields.
You just need to be aware that you might reject perfectly valid XML where it doesnât conform to your strict layout.
IOW what you are validating is your specific format - not XML in general. Jonâs idea of deleting tags in a queue is a good idea for more general XML.
One thing first - where you have code like:
STFL1.GetLine(XXML#)
IF XXML# = 1
IF ~STFL1.Instring('<MYREF')
! ERROR - Terminate - Notify customer
END
END
you need to understand that doing STFL1.getline() returns a value but does NOT put it into the STTFL1 value so the following check for STFL1.Instring(â<MYREFâ) will not do what you think.
what you would need to do is either
STFL1.setValueFromLine(XXML#)
or you could do it âlong handâ
STFL1.setvalue(STFL1.getLine(XXML#))
some people prefer to have a separate ST object for the line values either for clarity or if they are going to then do a further split on the line:
lne.setvalue(STFL1.getLine(XXML#))
anyway with that aside, given that you want a strict format with fields/elements in a certain order, perhaps first define the order in your data not in your code - this will make it much easier to maintain if new fields are added or your stict order is changed etc.
Elements STRING('MYREF,CARNO,DRIVER, ...and so on')
you can then put that in a ST object and split on the delimiter (comma in this case) to give a list and order of elements.
stElt StringTheory
code
stElt.setValue(Elements)
stElt.split(',',,,,st:clip,st:left)
remembering you have specified each element on a new line etc., you could then validate your input.
Note we will NOT do st.removeLines so that you can keep all lines so that you can report which line number an error is on.
elements STRING('MYREF,CARNO,DRIVER, ...and so on')
eltNum long
elt PString(256)
stElt StringTheory
st StringTheory
x long,auto
inRec long
errs long
code
stElt.setValue(Elements)
stElt.split(',',,,,st:clip,st:left)
if ~st.LoadFile(Loc:FileToImport)
message('Failed to load file ' & clip(Loc:FileToImport) & |
'||Error: '& st.LastError ,'File not Loaded')
! exit or return etc
end
st.split('<13,10>',,,,st:clip,st:left)
loop x = 1 to st.records()
st.setValueFromLine(x)
if ~st.getValue() then cycle. ! skip empty lines
if ~inrec
if st.getValue() = '<RECORD>'
inRec = true
eltNum = 0
end
cycle
end
if st.getValue() = '</RECORD>'
inRec = false
if eltNum <> stElt.records()
errs += 1
message('Was expecting ' & stElt.records() & |
' elements but got ' & eltNum, |
'Error on line ' & x,Icon:Exclamation)
! you might want to BREAK to abandon further validation
end
cycle
end
eltNum += 1
if eltNum > stElt.records()
errs += 1
message('Was expecting ' & stElt.records() & |
' elements but found element# ' & eltNum & |
'||' & st.getValue(), |
'Error on line ' & x,Icon:Exclamation)
cycle ! or you might want to BREAK to abandon further validation
end
elt = stElt.getLine(eltNum)
if ~st.startsWith('<<' & elt)
errs += 1
message('Was expecting ' & elt & ' element but got:||' & |
st.getValue(), |
'Error on line ' & x,Icon:Exclamation)
cycle ! or you might want to BREAK to abandon further validation
end
if st.getValue() = '<<' & elt & '/>' or |
(st.startsWith('<<' & elt & '>') and st.endsWith('<</' & elt & '>'))
! is valid
else
errs += 1
message('Was expecting either a value like||<<' & elt & '>' & |
'some value<</' & elt & '>||' & |
'or a null/empty value <<' & elt & '/>||' & |
'but got:||' & st.getValue(),|
'Error on line ' & x,Icon:Exclamation)
! you might want to BREAK to abandon further validation
end
end ! loop
if ~errs
if ~inrec
message('File is valid')
else
message('Missing final </RECORD> in file')
end
end
Anyway this should point you in the general direction and you can adapt this to your exact requirements.
I have put error messages in the code but perhaps you might choose to log these to a file etc. If you call a centalised error procedure you could put the messages or logging there and have a switch to swap between them.
One thing you will want to consider is if you want to abandon the validation once one error is found or keep going. I have indicated where you can BREAK out of the validation loop once an error is found (ie wherever an error is encountered).
I should add that this code is not tested in any way so caveat emptor and all that - but see how you go.
cheers
Geoff R
Edit 1 - check at end that not inrec (missing '</RECORD/>')
Edit 2 - split messages over multiple lines to try to remove horizontal scrolling