Question
· Nov 23, 2021

Not all XML child items are loaded into a class list when using XML.Reader correlate

Hi all

I'm new to ObjectScript and I've been experimenting the correlate method of %XML.Reader to convert an XML file I've loaded into its corresponding class. But, I have found that I am not getting all the child items of an element in a List contained within the converted class, only the last item.

The XML file content is as follows:

<Results>
  <PersonIDs>
    <PersonID>1000000</PersonID>
    <PersonID>1000001</PersonID>
    <PersonID>1000005</PersonID>
  </PersonIDs> 
</Results>

I have two classes: the parent SearchResultsMessage contains a List Of the child class PersonID, as shown below. This code is simplified and has had various non-relevant bits removed.

Class GMMHTIE.ParisConnect.WebClient.Messages.Response.PersonSearchResultsMessage Extends (%Persistent, %XML.Adaptor)
{
   Property PersonIDs As list Of PersonID(XMLNAME = "PersonIDs", XMLPROJECTION = "ELEMENT"); 
}

Class PersonID Extends (%Persistent, %XML.Adaptor)
{ 
    Property PersonID As %String(XMLNAME = "PersonID", XMLPROJECTION = "ELEMENT");
}

So, when I use correlate I have a class instance for SearchResultsMessage and I can confirm that it is picking up other properties correctly (which are not shown), but the property PersonIDs only contains one item, the last 1000005.

This is the code I'm using, which is abridged for brevity:

  Set reader = ##class(%XML.Reader).%New()
  Set sc=reader.OpenString( Set reader = ##class(%XML.Reader).%New()
  Set sc=reader.OpenString(pInput)
 
  Do reader.Correlate("Results","PersonSearchResultsMessage") 
  While reader.Next(.convertedMessage,.sc) {
        // success
!,"Count(): "_convertedMessage.PersonIDs.Count() 
        // A value of one is returned, expecting 3
   }

Can anyone help - what am I missing?

Cheers

Andy

Product version: IRIS 2020.1
$ZV: IRIS for Windows (x86-64) 2020.1 (Build 215U) Mon Mar 30 2020 20:14:33 EDT
Discussion (6)1
Log in or sign up to continue

When you're projecting a list of a class to XML, you usually have a parent element for each of those objects, then a separate element for each of it's properties. So I think what you'd need to do would be something more like:

<Results>
    <PersonIDs>
        <PersonID>
            <PersonID>1000000</PersonID>
        </PersonID>
        <PersonID>  
            <PersonID>1000001</PersonID>
        </PersonID>  
        <PersonID>  
            <PersonID>1000005</PersonID>
        </PersonID>  
    </PersonIDs> 
</Results>

So that the outer PersonID element indicates your PersonID object, and the PersonID inside of that is the PersonID property of that object.

I'll give it a try - how would I do that, I'm still new to objectscript at the moment.

Making the following change

 Property PersonIDs As list Of %String(XMLNAME = "PersonIDs", XMLPROJECTION = "ELEMENT");

Results in an error of:

ERROR #6232: Datatype validation failed for tag, PersonIDs (ending at line 9 character 15), with value:
1

Try it like this:

Class User.ResultsMessage Extends (%Persistent, %XML.Adaptor)
{

Property PersonIDs As list Of %String(XMLITEMNAME = "PersonID", XMLNAME = "PersonIDs", XMLPROJECTION = "WRAPPED");

XData Data
{
<Results>
  <PersonIDs>
    <PersonID>1000000</PersonID>
    <PersonID>1000001</PersonID>
    <PersonID>1000005</PersonID>
  </PersonIDs> 
</Results>
}

/// do ##class(User.ResultsMessage).Test()
ClassMethod Test()
{
	Set text = ##class(%Dictionary.XDataDefinition).IDKEYOpen($classname(), "Data").Data
	Set reader = ##class(%XML.Reader).%New()
	Set sc=reader.OpenStream(text)

	Do reader.Correlate("Results","User.ResultsMessage") 
	While reader.Next(.msg,.sc) {
		Write !,"Count(): "_msg.PersonIDs.Count(),!
	}
	Write:$$$ISERR(sc) $System.Status.GetErrorText(sc)
}
}

Docs.