Web Connection
XMLTOOBJECT fails when processing collection
Gravatar is a globally recognized avatar based on your email address. XMLTOOBJECT fails when processing collection
  Rodney
  All
  May 5, 2017 @ 07:17am

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.)



Gravatar is a globally recognized avatar based on your email address. re: XMLTOOBJECT fails when processing collection
  Rick Strahl
  Rodney
  May 5, 2017 @ 06:55pm

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 ---

© 1996-2024