Hi
I am trying to convert xml to an object with xmltoobject. The XML / object has a few collections in it but as soon as it tries to parsexmltocollection it fails with "Member SELECTSINGLENODE does not eval...."
Cant figure it out if I am missing something when I set my object up or ...
TEXT TO lcXml NOSHOW
<xdoc>
<SessionGroups>
<SessionGroup Name="Morning Sessions" ID="20104">
<Session>
<ID>2001</ID>
<Name>Meet and Greet</Name>
<Description>Come meet your speakers and mingle with other conference attendees!</Description>
<Presenter></Presenter>
<SeatLimit></SeatLimit>
<StartDateTime>2011-04-18 09:00:00</StartDateTime>
<EndDateTime>2011-04-18 09:59:59</EndDateTime>
<CreatedDate>2010-08-03 11:42:19</CreatedDate>
<UpdatedDate>2010-08-03 11:42:19</UpdatedDate>
</Session>
<Session>
<ID>2002</ID>
<Name>Keynote Address</Name>
<Description>Hear the latest updates from our president.</Description>
<Presenter>Brenda Smith</Presenter>
<SeatLimit>200</SeatLimit>
<StartDateTime>2011-04-18 10:15:00</StartDateTime>
<EndDateTime>2011-04-18 11:29:59</EndDateTime>
<CreatedDate>2010-08-03 11:53:31</CreatedDate>
<UpdatedDate>2010-08-03 11:53:31</UpdatedDate>
</Session>
</SessionGroup>
<SessionGroup Name="Afternoon Sessions" ID="20105">
<Session>
<ID>2003</ID>
<Name>The Future of Our Chapter</Name>
<Description>Learn about upcoming events and other exciting developments coming up in our organization's future.</Description>
<Presenter>Michael Henderson</Presenter>
<SeatLimit>175</SeatLimit>
<StartDateTime>2011-04-18 14:00:00</StartDateTime>
<EndDateTime>2011-04-18 15:59:59</EndDateTime>
<CreatedDate>2010-08-03 12:15:44</CreatedDate>
<UpdatedDate>2010-08-03 12:15:44</UpdatedDate>
</Session>
</SessionGroup>
</SessionGroups>
</xdoc>
ENDTEXT
loSessionGroups=CREATEOBJECT("EMPTY")
ADDproperty(loSessionGroups,"SessionGroup",CREATEOBJECT("collection"))
loitem=CREATEOBJECT("EMPTY")
ADDproperty(loItem,"ID",0)
ADDproperty(loItem,"Name","")
ADDproperty(loItem,"Description","")
ADDproperty(loItem,"Presenter","")
ADDproperty(loItem,"SeatLimit",100)
ADDproperty(loItem,"StartDateTime",DATETIME())
ADDproperty(loItem,"EndDateTime",DATETIME())
ADDproperty(loItem,"CreatedDate",DATETIME())
ADDproperty(loItem,"UpdatedDate",DATETIME())
ADDproperty(loSessionGroups,"SessionGroup",CREATEOBJECT("collection"))
ADDproperty(loSessionGroups.SessionGroup,"Session",CREATEOBJECT("collection"))
loSessionGroups.SessionGroup.Session.ADD(loItem)
oX=CREATEOBJECT("WWXML")
ox.lrecurseobjects=.t.
lo1=ox.XMLTOOBJECT(lcXml,losessiongroups,.t.)
The collection parser requires a very specific structure in order to work correctly. It doesn't just work off arbitrary structure and element names. You might have more luck with arrays instead.
Looking at the code, it looks like collections don't even go two-way. This work was never completed I'm guessing. Checking now...
update
So I took a look and things are definitely broken both in the output generation and the capture - it doesn't work two-way at this point.
With a couple of fixes I was able to make this work:
clear
loSessionGroups=CREATEOBJECT("EMPTY")
ADDproperty(loSessionGroups,"SessionGroup",CREATEOBJECT("collection"))
loitem=CREATEOBJECT("EMPTY")
ADDproperty(loItem,"ID",0)
ADDproperty(loItem,"Name","")
ADDproperty(loItem,"Description","")
ADDproperty(loItem,"Presenter","")
ADDproperty(loItem,"SeatLimit",100)
ADDproperty(loItem,"StartDateTime",DATETIME())
ADDproperty(loItem,"EndDateTime",DATETIME())
ADDproperty(loItem,"CreatedDate",DATETIME())
ADDproperty(loItem,"UpdatedDate",DATETIME())
ADDproperty(loSessionGroups,"SessionGroup",CREATEOBJECT("collection"))
loSessionGroups.SessionGroup.Add(loItem)
loSessionGroups.SessionGroup.Add(loItem)
oX=CREATEOBJECT("WWXML")
ox.lrecurseobjects=.t.
lcXml = ox.ObjectToXml(loSessionGroups,"sessiongroups")
_cliptext = lcxml
? lcXml
lo1=ox.XMLTOOBJECT(lcXml,losessiongroups,.t.)
? lo1.sessiongroup.Count
? lo1.sessiongroup[1].seatlimit
? lo1.sessiongroup[1].startdatetime
RETURN
which produces XML like this for the collection:
<?xml version="1.0"?>
<xdoc>
<sessiongroups type="object" class="empty">
<sessiongroup>
<count>2</count>
<items>
<item type="object" class="empty">
<createddate>2017-05-05T19:11:04</createddate>
<description></description>
<enddatetime>2017-05-05T19:11:04</enddatetime>
<id>0</id>
<presenter></presenter>
<seatlimit>100</seatlimit>
<startdatetime>2017-05-05T19:11:04</startdatetime>
<updateddate>2017-05-05T19:11:04</updateddate>
</item>
<item type="object" class="empty">
<createddate>2017-05-05T19:11:04</createddate>
<description></description>
<enddatetime>2017-05-05T19:11:04</enddatetime>
<id>0</id>
<presenter></presenter>
<seatlimit>100</seatlimit>
<startdatetime>2017-05-05T19:11:04</startdatetime>
<updateddate>2017-05-05T19:11:04</updateddate>
</item>
</items>
</sessiongroup>
</sessiongroups>
</xdoc>
The reason for this is that collections have a number of additional properties like Count and KeySort that have to be set and so the structure for the collection is more complex.
The fixes are as follows:
in ParseXmlToCollection()
loKeySort = loXmlObject.SelectSingleNode("keysort")
IF !ISNULL(loKeySort)
loCollection.KeySort = VAL(loKeySort.text)
ENDIF
in CreateCollectionXml()
lcOutput = REPLICATE(CHR(9),lnIndent) + "<" + lcName + ">" + CRLF +;
REPLICATE(CHR(9),lnIndent + 1) + "<count>" + TRANSFORM(lnItems) + "</count>" + CRLF + ;
REPLICATE(CHR(9),lnIndent + 1) + "<items>" + CRLF
FOR lnX=1 TO lnItems
lvValue = loCollection.Item[lnX]
lcType = VARTYPE(lvValue)
lcField = lcRow
lcOutput = lcOutput + this.AddElement(lcRow,@lvValue,lnIndent + 2,;
IIF(lcType # "O",[key="] + loCollection.GetKey(lnX) +[" type="] + lcType + ["],;
[key="] + loCollection.GetKey(lnX)+ ["]))
ENDFOR
RETURN lcOutput + ;
REPLICATE(CHR(9),lnIndent + 1) + "</items>" + CRLF + ;
REPLICATE(CHR(9),lnIndent) + "</" + lcName + ">" + CRLF
If you use Arrays instead of collections you can deserialize the more basic object structure.
+++ Rick ---